Do not open a public issue for a security problem.
Report privately to atom.support@npci.org.in, with [SECURITY]
at the start of the subject line.
That address is the project's shared open-source inbox and is monitored by the maintainers of both this repository and the Authority platform; the subject-line tag is what routes it for triage ahead of general correspondence. One inbox covers both because the A2A contract spans both, and a wire-protocol finding usually affects each side.
A good vulnerability report includes:
- Description — what the vulnerability is and its potential impact.
- Steps to reproduce — a minimal, reliable reproduction path.
- Affected component — which service, file, or endpoint is affected.
- Suggested fix — optional, but appreciated.
- Your contact details — so we can keep you updated and credit you.
| Stage | Target |
|---|---|
| Acknowledgement | Within 48 hours of receipt |
| Initial assessment | Within 5 business days |
| Fix or mitigation | Within 30 days for critical; 90 days for others |
| Public disclosure | Coordinated with reporter after fix is released |
We follow a coordinated disclosure model. We will not take legal action against researchers who report vulnerabilities in good faith and follow this policy.
- The partner backend (
backend/app/), including the A2A wire code inbackend/app/a2a_common/as it exists in this repository - The agent framework and the shipped reference agents (
backend/app/agents/) - The frontend (
frontend/) - Authentication, session handling, and the settings/credential surface
- The GitLab integration (
backend/app/services/git_integrator.py) - Container and Compose configuration in this repository
- The Authority platform. It lives in its own repository — report against https://github.com/npci/atom-network-platform instead. Findings in the shared A2A code as it exists here remain in scope here, and we will coordinate the fix across both.
- Your fork's agent bodies. This is reference base code; the agents are meant to be replaced. Findings in the framework are in scope, findings in your own replacement logic are not.
- Vulnerabilities in third-party dependencies (report those upstream)
- Social engineering attacks
- Physical security
- Denial-of-service attacks that require significant resources
Pre-1.0. Only main receives fixes. There is no long-term-support branch and
no backporting.
This platform receives documents from an external party, feeds them to a model with tools, generates code, and drives git. That is a larger blast radius than a typical web application, and the honest posture matters more than a reassuring one.
Change communications, Product Kit documents, and retrieved code chunks are untrusted input that reaches a model. They arrive over the A2A wire from the Authority and are chunked into a retrieval corpus. Generated code is gated behind a human-opened merge request.
None of that is a proof. A sufficiently clever document may still influence generated output. Treat every generated artifact as a proposal requiring human review, never as an authority.
git_integrator.open_merge_request()creates a branch, commits files, and opens a merge request. It never merges — that is enforced in code, and it should stay that way in your fork.- Nothing is deployed by this platform.
- Feasibility assessments, progress reports and readiness declarations are sent to the Authority. Review before dispatch; a wrong readiness declaration is a business event, not just a bug.
- Never expose the backend directly. Do not add a
ports:publish to the backend service indocker-compose.yml; it is intentionally reachable only through theedgeproxy, which terminates TLS. - Set a strong
ADMIN_PASSWORDbefore first start. The service refuses to seed an admin account without one — there is no default password. Keep the value out of version control and rotate it if it may have leaked. - Set
SESSION_JWT_SECRETexplicitly. It has no safe default. Sessions signed with a guessable secret are forgeable. - Protect the Authority-issued credentials. The partner API key and the JWT/HMAC secrets are entered through the Settings UI and stored per deployment. Anyone with admin access to this platform can act as your organisation on the A2A wire.
- Give the platform the narrowest GitLab token that works. A token that can push to a default branch is a token an injected prompt can try to use. It needs enough to create a branch and open a merge request, and no more.
- Keep the CORS allowlist tight. The allowlist is derived from the
configured authority URL plus
PARTNER_CORS_EXTRA_ORIGINS; a literal*in that variable is rejected at startup. List extra origins explicitly, and do not reintroduce a wildcard.
We would rather tell you than have you find out:
- Login lockout and the JWT denylist are in-memory and single-instance.
backend/app/api/auth.pykeeps both in process dictionaries. Run more than one replica and a revoked token stays valid on the other replicas, and lockout counters are per-process. There is no CAPTCHA on login — the tiered lockout (5 failures → 60s, 10 → 5 min) is the only brute-force control. - Nonce replay protection is active, backed by the database.
hmac_middleware.pywires a nonce store intohmac_signer.verify()viaa2a_common/nonce_store_db.py: Redis-backed where a Redis is deployed, Postgres-backed otherwise. The store fails closed — if it errors, the request is rejected rather than waved through — so a captured request cannot be replayed even within the 5-minute timestamp window. - Only one of the three supported LLM providers has a dedicated secret-scan
rule.
.gitleaks.tomlsetsuseDefault = true, so the upstream gitleaks ruleset applies and the three custom rules (the A2A partner API key, Anthropic keys, GitLab PATs) sit on top of it. Broad formats are therefore covered generically — the repo's own allowlist records ageneric-api-keyhit — but a key forpartner_ainxt_api_key, whose format is defined by whatever gateway an operator points at, matches no targeted rule and is caught only if it trips a default heuristic. Treat per-provider coverage as uneven, not absent. - Dependencies include several LGPL-licensed packages — see
THIRD-PARTY-NOTICES.mdif that matters to you.
- Signature comparison is constant-time (
hmac.compare_digest). - The nonce path fails closed. If the nonce store errors,
verify()logs critical and rejects rather than waving the request through. The previousHMAC_FAIL_OPENescape hatch was removed deliberately. - The Python image installs from a hash-locked closure with
--require-hashes, so a substituted artifact at a pinned version fails the build.
The A2A envelope is HMAC-SHA256 over a canonical string-to-sign, verified with a
constant-time compare inside a 5-minute timestamp window. Replay protection is
wired and active: a database-backed nonce store
(a2a_common/nonce_store_db.py, Redis-backed where deployed) rejects reuse and
fails closed. Session tokens are HS256. Passwords are bcrypt.
That symmetric layer needs no post-quantum migration: HMAC-SHA256 and bcrypt are not threatened by Shor's algorithm, and the Grover speed-up is answered by the key sizes already in use. TLS is terminated by whatever proxy you deploy in front, so the transport posture — including any hybrid post-quantum key exchange — is yours to set, not this repository's.
The A2A contract code is mirrored with the Authority platform. A change to
hmac_signer.py must land on both sides as a coordinated release, or live
calls start failing signature verification while both test suites still pass.
gitleaks runs on every push and pull request
(.github/workflows/secret-scan.yml),
scanning both the working tree and the full history, and blocks the build on a
hit. Its rule coverage is narrow (see "Known gaps" above), so these still apply:
- Never commit
backend/.env. Onlybackend/.env.example, with empty values, belongs in git. - Authority-issued credentials go through the Settings UI, never into a file under version control.
- The example partner profiles in
data/are illustrative. Do not replace them with a real internal capability document and commit it.
Widening the gitleaks rule set to cover the remaining provider key formats is
a welcome contribution — see CONTRIBUTING.md.
This security policy is part of the Partner Platform, licensed under the MIT License. See LICENSE for details.