| Version | Supported |
|---|---|
main |
✅ Active security patches |
< 1.0 |
❌ No longer supported |
Only the latest commit on main receives security patches at this stage of the project. Pin to a specific commit SHA if you need a stable, audited snapshot.
Do not open a public GitHub issue for security vulnerabilities.
Use GitHub Private Security Advisories to report vulnerabilities confidentially. This keeps details private until a fix is released.
| Milestone | Target |
|---|---|
| Acknowledgement | ≤ 48 hours |
| Initial triage & severity assessment | ≤ 5 business days |
| Patch or mitigation for Critical/High | ≤ 14 days |
| Patch or mitigation for Medium/Low | ≤ 30 days |
| Public disclosure (coordinated) | After patch is released |
We follow coordinated vulnerability disclosure. Researchers who report responsibly will be credited in the release notes unless they prefer anonymity.
The following invariants are enforced throughout the codebase. Any contribution that weakens them will be rejected.
All sensitive credentials — AGENT_SECRET_KEY, RPC endpoints, asset issuers — are sourced exclusively from environment variables and validated at startup via Zod schemas (backend/config.ts). No secrets appear in source code, committed configuration files, or log output.
Enforcement:
.envis.gitignored;.env.examplecontains only placeholder values.- Zod validation error messages strip any value matching a Stellar secret-key pattern (
S[A-Z2-7]{55}) before writing to stderr (formatValidationErrorsinbackend/config.ts). - CI pipelines must never inject real secret keys into build logs.
Every Soroban transaction is passed through prepareSorobanTx (Soroban RPC simulation) before it is signed or broadcast. Simulation catches fee estimation errors, authorization failures, and contract-level panics without spending funds or mutating on-chain state.
Enforcement:
- The sign → submit path is only reachable after a successful simulation response.
- A failed simulation aborts the operation and surfaces a structured error to the agent loop, preventing silent fund loss.
Before any x402 payment is triggered, the incoming challenge is validated for:
- Schema correctness — all required fields present and correctly typed.
- Expiry — the challenge timestamp is within the accepted window; stale challenges are rejected.
- Asset match — the requested asset code and issuer are compared against the agent's configured
X402_ASSET_CODE/X402_ASSET_ISSUERvalues.
Enforcement:
- Validation runs before any keypair access or transaction construction.
- Challenges failing any check are dropped without triggering a payment.
AGENT_SECRET_KEY has a single, controlled access path in the entire codebase.
// 1. Raw secret parsed from env — never leaves this scope
const { AGENT_SECRET_KEY: _secret, AGENT_PUBLIC_KEY: _rawPub, ...rest } = raw;
// 2. AgentConfig interface explicitly excludes the secret key
export interface AgentConfig extends Omit<RawEnv, "AGENT_SECRET_KEY" | "AGENT_PUBLIC_KEY"> {
readonly AGENT_PUBLIC_KEY: string; // safe to log
readonly agentKeypair: () => Keypair; // explicit, call-site access only
}
// 3. Secret captured in closure — never placed on the config object
const cfg: AgentConfig = {
...rest,
AGENT_PUBLIC_KEY: derivedPublicKey,
agentKeypair: () => Keypair.fromSecret(_secret),
};| Risk | Mitigation |
|---|---|
Accidental console.log(config) leaks the secret |
Secret is absent from the config object entirely — it only exists inside the loadConfig closure scope. |
Serialization (e.g. JSON.stringify(config)) captures the secret |
agentKeypair is a function reference; functions are silently dropped by JSON serialization. |
| Log aggregators capturing structured config objects | AGENT_SECRET_KEY is removed via destructuring before cfg is constructed; it cannot appear in any downstream spread. |
| Zod validation errors echoing the raw value | formatValidationErrors applies a regex redaction pass over all error messages before writing to stderr. |
Calling convention: code that needs to sign a transaction must call config.agentKeypair() explicitly. This deliberate friction makes secret access visible at review time and auditable via static analysis.
- Mainnet spending cap:
AGENT_SPENDING_LIMITis rejected at startup if it exceeds10,000onmainnet, preventing runaway agent spend. - Exponential back-off: All RPC calls use retry logic with jitter to reduce the attack surface of timing-based denial-of-service against the agent.
- Dependency pinning: Keep
package.jsondependencies pinned to exact versions and audit regularly withnpm audit.