This document describes the security posture, data handling, and responsible-use boundaries of this repository. It is written for a local, single-user product prototype — it does not claim, and should not be read as claiming, production-grade security engineering.
This repository contains Sentinel, an independent merchant-facing AI Risk Manager product prototype built for the Razorpay Buildathon (Track 02). It includes a FastAPI backend, a React dashboard, and an AI orchestration layer, with its risk intelligence built and evaluated using a synthetic data generator and an ML training/evaluation pipeline.
Sentinel is not part of Razorpay's infrastructure. It does not run inside Razorpay's systems, does not connect to any Razorpay service, and does not have access to Razorpay's real risk engine, dispute infrastructure, merchant accounts, or transaction data. Every claim in this document concerns this prototype's own code and data only.
This document covers: what data the prototype touches, how secrets are expected to be supplied locally, the AI layer's safety boundaries, the model's evaluated limitations, the boundary with Razorpay's real systems, and how to report a security issue in this codebase. It does not cover deployment hardening, infrastructure security, or compliance — none of that exists in this repository today (see §9).
Sentinel does not contain, require, or process any real merchant or
customer payment data. Every dataset in this repository (data/) is
generated by ml/data_generation/ from a fixed random seed — a fully
synthetic 50-merchant × 180-day benchmark with explicit, documented
modeling assumptions (docs/architecture/data_generation.md). No
number in the dataset originates from Razorpay, from any real
merchant, or from any real transaction.
The backend loads this synthetic data and the trained model artifact
once at startup, entirely from local disk, and serves it read-only —
there is no database and no persistence layer
(docs/architecture/backend.md). The one partial exception is
Merchant Risk Memory: an in-process, session-scoped record of
intervention/simulation activity, held only in server memory and
cleared on every backend restart — never written to disk, never a
database (docs/architecture/intervention_intelligence.md).
What this repository does not claim: encryption at rest or in transit beyond what your local machine's OS/filesystem and HTTPS (if you put a TLS-terminating proxy in front of it yourself) already provide, any compliance certification, or any production-grade secrets vault. None of these are implemented here, and this document does not assert otherwise.
Sentinel reads all secrets from environment variables, never from
a committed file. .env and every .env.* file are excluded from
version control by .gitignore — the only environment file tracked in
the repository is .env.example (and apps/dashboard/.env.example),
which contains empty placeholders only.
Verified against the current repository:
| Variable | File | Purpose |
|---|---|---|
SENTINEL_AI_PROVIDER |
.env.example |
Selects the AI provider: mock (default, no network calls), openai, or featherless |
OPENAI_API_KEY |
.env.example (commented placeholder) |
Real OpenAI provider only |
SENTINEL_AI_MODEL |
.env.example (commented placeholder) |
Real OpenAI provider only |
FEATHERLESS_API_KEY |
.env.example |
Featherless.ai provider only |
FEATHERLESS_BASE_URL |
.env.example |
Featherless.ai provider only |
FEATHERLESS_MODEL |
.env.example |
Featherless.ai provider only |
VITE_API_BASE_URL |
apps/dashboard/.env.example |
Backend URL the dashboard calls — not a secret, but still kept out of source control by convention |
The backend does not use python-dotenv or any automatic .env
loader — variables must be exported into the shell before starting the
backend (e.g. set -a && source .env && set +a), which is itself a
deliberate way of making "where did this secret come from" explicit
rather than implicit (docs/architecture/ai_orchestrator.md).
Never commit a real API key, token, or .env file. If a real
OpenAI or Featherless.ai key is ever used locally for a demo, treat it
as a live credential: keep it out of commits, screenshots, logs, and
shared terminal recordings, and rotate it if it is ever exposed.
If a provider is misconfigured or its API key is missing, the backend
does not crash — it falls back to a clean "provider unavailable"
response (503), and no internal filesystem path, credential, or raw
provider exception is ever included in an API response
(docs/architecture/ai_orchestrator.md).
Sentinel's AI assistant explains already-computed results. It does
not, and structurally cannot, independently calculate risk, exposure,
liquidity, SHAP values, or simulation output — every number it
discusses is computed by an existing backend service before the AI
provider is ever called (backend/ai/context_builder.py), and a test
independently verifies the assistant's cited numbers are
byte-identical to the same authoritative service call every dashboard
screen makes.
Every value Sentinel surfaces — through the dashboard or the assistant — is labeled by provenance, and the AI layer is instructed never to blur these together:
- Observed — read directly from data.
- Modeled — output of the trained, evaluated classifier.
- Derived — transparent arithmetic on observed/modeled values, not a model.
- Synthetic / prototype assumption — a disclosed benchmark or evidence-readiness heuristic, not a verified fact.
The system prompt (backend/ai/prompt.py) instructs the model, on
every call, not to fabricate evidence, not to claim access to
Razorpay's proprietary systems, not to make causal or guaranteed
claims about simulated impact, and not to claim a real-world
intervention outcome exists (none does — see §5). A deterministic
pre-filter (backend/ai/guardrails.py) checks every incoming question
for known prompt-injection phrasings before any provider is called; a
second, prompt-level instruction tells the model to treat the user's
own message as untrusted input. This defense is not absolute — a
sufficiently indirect or novel injection attempt against a real
provider is bounded only by that provider's own instruction-following,
which cannot be guaranteed.
Generated assistant text is not an authoritative financial, legal, or operational decision. It is a natural-language explanation of Sentinel's own verified, already-computed, synthetic-benchmark output — nothing more. A response generated by a real provider (OpenAI or Featherless.ai) is always labeled with the exact provider/model identifier that produced it, and the deterministic mock provider (the default) is always labeled as such, so the two can never be visually confused.
Every risk score, exposure figure, and driver explanation in Sentinel comes from a model trained and evaluated entirely on the synthetic 50×180 benchmark described in §2 — never on real transactions. Benchmark performance is not, and must not be read as, production validation or a claim about real-world predictive accuracy.
Documented, evaluated limitations that materially affect how these
numbers should be interpreted (full detail in EVALUATION.md):
- Calibration: post-hoc calibration (Platt/sigmoid scaling) was evaluated for the selected model and did not improve its Brier score — the model's probabilities should be read as directionally useful for ranking risk, not as literal well-calibrated probabilities.
- Temporal shift / generalization: the selected 30-day candidate's PR-AUC drops materially (0.603 → 0.476) when evaluated on a later time period it never trained on — it does not survive distribution shift cleanly.
- Hard negatives: the benchmark's growth-is-not-risk contrast holds in aggregate but fails on at least one specific scenario type (a 100% false-positive rate on a small sample) — a genuine, unresolved weak point, not a clean pass.
- Exposure regression: a regression model for future chargeback exposure amount did not outperform a simple trailing-average baseline, so no exposure-prediction model is used in the product — the exposure figure shown is a transparent, disclosed derivation.
- Causal / intervention interpretation: SHAP explains what the model's own inputs did to its output — never that a feature causes real-world risk. Simulator output is a bounded what-if estimate ("MODELED IMPACT") against the same trained classifier — never a causal guarantee or a promise of real-world impact.
Sentinel does not claim, anywhere in this codebase or its documentation, access to:
- Razorpay's proprietary risk-scoring or enforcement systems,
- Razorpay's real dispute/chargeback infrastructure,
- any real Razorpay merchant or customer data, or
- any real card-network or issuer reason-code taxonomy.
Sentinel's own reason-code taxonomy is an explicitly labeled synthetic
prototype construct, repeated as a disclaimer on every relevant API
response (backend/evidence/reason_codes.py,
docs/architecture/incident_response.md) — never presented as
Razorpay's, a card network's, or any real dispute system's actual
taxonomy.
Sentinel's incident/evidence workflow never fabricates evidence
(no invoice, tracking number, or message body is ever invented — every
evidence category resolves to available/missing via a disclosed rule)
and never submits a real dispute. There is intentionally no
mutating incident or evidence endpoint anywhere in the backend — every
registered route in that area is GET-only, and this is directly
tested (docs/architecture/incident_response.md). The response-
preparation workflow states explicitly that nothing is submitted
anywhere and that a real submission would require Razorpay's actual
dispute process, which Sentinel does not have access to.
This repository does not currently maintain a dedicated security contact address or a formal disclosure program. No such contact should be assumed or inferred from this document.
If you find a security issue in this repository, please open an issue on this project's GitHub repository so the maintainer can review it. For anything you believe should not be public before a fix is available, note that clearly in the issue and keep exploit details minimal until it has been addressed — there is no private triage channel available today, so use your judgment about what to include in a public report.
Sentinel is a local development product prototype, run on a
developer's own machine. There is no deployed, shared, or multi-tenant
instance described anywhere in this repository. Keep your local .env
file(s) and any real API credentials private — do not paste them into
issues, commit messages, screenshots, terminal recordings, or shared
documents. The backend's CORS policy is intentionally permissive for
local development (any localhost/127.0.0.1 port is allowed,
documented directly in backend/api/main.py) and is explicitly not
a production-appropriate policy — it should not be reused as-is if this
project is ever deployed beyond a developer's own machine.
Stated explicitly, not implied:
- No authentication, authorization, or user accounts anywhere in the backend.
- No database — Merchant Risk Memory is the one stateful exception, and it is in-process, session-scoped, and cleared on every restart.
- No production-grade secrets management — secrets are plain environment variables, suitable for local development only.
- No encryption-at-rest or in-transit controls implemented by this project itself — whatever your local environment/proxy provides is all that applies.
- No compliance certification of any kind (not SOC 2, not PCI DSS, not ISO 27001, not any other framework) — none has been pursued or claimed.
- No formal threat model, penetration test, or third-party security review has been performed on this codebase.
- CORS is permissive by design for local development, not hardened for a shared or public deployment (§8).
- The AI prompt-injection defense is not absolute — see §4.
- Sentinel's risk intelligence is built and evaluated on a synthetic benchmark — see §5. Model outputs, simulator results, and intervention recommendations are not validated against real-world data or real-world outcomes.