The agenc-coordination Solana program is a custodial smart contract: it holds
task escrow, completion bonds, and reputation stakes on behalf of
third parties. A vulnerability here can directly cause loss or lock of user
funds. We take reports seriously and commit to the response process below.
This policy covers the on-chain program, the SDK packages published from this repository, and the tetsuo-ai hosted rails (indexer, moderation attestation, artifact storage) that integrators may optionally depend on.
Report privately. Do not open a public GitHub issue, PR, or discussion for a suspected security vulnerability.
Use GitHub Private Vulnerability Reporting. It is enabled for this repository and keeps the report private between the reporter and repository administrators. Do not send exploit details through a public issue.
[email protected] is not advertised because mailbox delivery and alerting
have not been verified. Add it only after an operator completes an end-to-end
test. The checked-in .well-known/security.txt therefore names the confirmed
GitHub private-advisory channel as the required contact. Run
node scripts/enterprise-readiness.mjs after each hosted deployment to verify
that PVR remains enabled and both public metadata endpoints serve the exact
active policy.
- What to include: affected component (program instruction / SDK / hosted
rail), program ID + cluster, a description of the impact (fund loss, fund
lock, unauthorized state transition, DoS), and a reproduction (a failing test,
a transaction, or a localnet script — see
docs/LOCALNET.mdandscripts/localnet-up.mjsfor a one-command full-surface validator).
Severity and reward priority follow the money-path-first ordering also used
by the bug bounty (docs/BUG_BOUNTY.md).
Mainnet runs revision 5 (101 instructions, surface_revision = 5), deployed
2026-07-22 through the Squads v4 2-of-3 vault (deployed executable SHA-256
049a66e30da166c1e02ee379993425c32386f774fd9ff8861153e21900b496f2). The explicit
104-instruction private-zk build is development-only and is rejected by the
production deployment rail.
The on-chain program HJsZ53Zb27b8QMRbQpuDngE44AdwCGxvEZr61Zmxw1xK
(programs/agenc-coordination/), specifically:
- Escrow custody and settlement —
create_task,cancel_task,accept_task_result/auto_accept_task_result,reject_task_result,complete_task, and the dispute settlement paths. Deployed revision 5 excludes thecomplete_task_privateABI entirely; the ZK/private-task surface remains deferred (noZkConfiginitialized). Any way to drain, double-spend, mis-route, or permanently lock escrowed SOL or SPL reward tokens. - Completion bonds —
post_completion_bond,reclaim_completion_bond, and bond disposition inside cancel / dispute / reject-frozen settlement. The 25% symmetric bond must be refunded or forfeited to the correct party. - Reputation stakes —
stake_reputation,withdraw_reputation_stake,delegate_reputation,revoke_delegation, and slashing (apply_dispute_slash,apply_initiator_slash). - Fee accounting — protocol / operator / referrer fee math in
completion_helpers.rs. The combined fee cap (MAX_COMBINED_FEE_BPS = 4000, i.e. the worker always keeps ≥ 60%) and the per-leg caps (MAX_PROTOCOL_FEE_BPS,MAX_OPERATOR_FEE_BPS,MAX_REFERRER_FEE_BPS, each 2000) are bytecode invariants; a bypass is in scope. - Authorization / state-machine integrity — any unauthorized state transition, PDA-substitution, account-confusion, missing-signer, or arithmetic bug that lets a non-owner move funds or escape a guard.
- Migration safety —
migrate_task/migrate_protocolcorrectness against the live account layout (the live program has real Task accounts; a bad migration is irreversible).
- Moderation attestation — the marketplace-managed attestor used by the
fail-closed moderation gate (
record_task_moderation/record_listing_moderation). Forged or replayed attestations, or a bypass of the fail-closed property. - Indexer / query API — the hosted read path. Note the SDK can read without
the hosted indexer via the on-chain gPA path (
listActiveListings); a hosted read-path issue that returns wrong data influencing a signed transaction is in scope. - Artifact storage — the hosted job-spec / artifact pipeline
(
docs/ARTIFACT_PIPELINE.md).
These are operated on hosted domains [HUMAN: enumerate the exact hostnames]. Test only against your own tasks/listings; do not attack other users' data.
@tetsuo-ai/protocoland@tetsuo-ai/marketplace-sdk(packages/). Client bugs that assemble an unsafe transaction, mis-decode on-chain state in a way that misleads a signer, or leak secrets.
- The hosted web UIs / landing pages unless a finding leads to fund loss, signed-transaction tampering, or attestation forgery.
- Findings that require a compromised upgrade authority, a malicious protocol authority/multisig, or a malicious assigned dispute resolver — those are trusted roles (see §5.3). Report governance-design concerns separately; they are not paid as vulnerabilities.
- Spam / rate-limiting of public RPC, third-party RPC providers, denial of service requiring unrealistic transaction volume or fees, and clickjacking on pages with no sensitive action.
- Anything already documented as a known limitation in
docs/audit/or the bug-bounty exclusions.
We aim to meet the following timelines once a report reaches a verified private channel. No professional external-audit report is currently published; internal adversarial work and green gates are evidence, not a substitute. GitHub Private Vulnerability Reporting is the verified private channel for these targets; the unverified mailbox described in §1 is intentionally not advertised.
| Stage | Target |
|---|---|
| Acknowledge receipt of your report | 2 business days |
| Triage — confirm/deny, assign severity | 5 business days |
| Fix developed for a confirmed Critical/High (fund loss or lock) | target 14 days; coordinated if a deploy + a task-layout migration choreography is required (the live Task corpus was 169 at the 2026-06-11 full-surface upgrade) |
| Fix for Medium/Low | next release window |
| Public disclosure | coordinated, after a fix is deployed; default embargo up to 90 days, extendable by mutual agreement for an on-chain fix that needs a gated upgrade |
We will keep you updated through triage and remediation, and we credit reporters who want credit (opt-out available).
We will not pursue or support legal action against, and we consider authorized, good-faith security research that:
- makes a genuine effort to avoid privacy violations, data destruction, and interruption or degradation of services;
- uses only your own accounts, tasks, listings, and funds for testing, and
prefers localnet/devnet over mainnet (use
scripts/localnet-up.mjsfor a full-surface local validator); - does not exploit a finding beyond the minimum needed to prove it, does not move or withhold other users' funds, and does not run mainnet exploits for profit;
- gives us reasonable time to remediate before public disclosure (see §3); and
- does not violate any other applicable law.
If you make a good-faith effort to comply with this policy during your research, we will consider your research authorized, work with you to understand and resolve the issue quickly, and will not recommend or pursue legal action related to your report. This safe harbor does not extend to actions taken against third parties (e.g. RPC providers, hosting vendors), and it does not waive their terms. This is a good-faith statement, not legal advice; [HUMAN: have counsel review before publication].
Integrators building on the program inherit three operational properties. Each is grounded in the actual on-chain code.
The protocol authority (a multisig — see §5.3) can pause the protocol and/or
disable specific task types via update_launch_controls
(programs/agenc-coordination/src/instructions/update_launch_controls.rs):
protocol_paused = truesetsProtocolConfig.protocol_paused.disabled_task_type_maskdisables individual task types.- The call is multisig-threshold gated (
require_multisig_threshold); a single key cannot pause.
Pause is an ENTRY control, not a fund trap. check_version_compatible
(entry paths) rejects when paused; check_version_compatible_for_exit
(programs/agenc-coordination/src/utils/version.rs) deliberately does not
consider protocol_paused. So a pause stops new work (task creation, claims,
bids) but never blocks the exit/settlement paths in §5.2. This is the
encoded "money never locks" invariant (spec §7, Decision #4), and it is
revert-sensitively unit-tested in version.rs. Tests establish intended
behavior for covered cases; they are not a guarantee that no unknown bug exists.
The intended invariant is that every escrowed task has at least one path that
releases funds even while the protocol is paused. The paths below were inspected
against program source — each exit calls check_version_compatible_for_exit —
but this inventory is not a claim of formal verification:
Exit paths present in the 25-instruction canary build (allowlist —
scripts/check-canary-idl.mjs) and live on the full mainnet surface
(the live full surface is revision 5 at 101 instructions; the first
84-instruction full build went live on 2026-06-11):
cancel_task— creator refund. Refundsescrow.amount - escrow.distributedto the creator (SOL or SPL), closes the escrow PDA, closes worker claim accounts (returning claim rent to the worker authority), and on the full surface refunds the creator's completion bond / forfeits a no-show worker bond. Allowed onOpentasks and onInProgresstasks past deadline with no completion.expire_claim— permissionless stale-claim cleanup after the claim deadline (with a 60s grace window where only the worker can self-expire, to block expiry-racing griefing — issue #421). Lets an abandoned claim be cleared so the task can be re-worked or cancelled.reject_task_result— routes aPendingValidation(CreatorReview) submission to rejection / review / refund; works while paused.accept_task_result— settle a completed submission to the worker (with capped fees). (auto_accept_task_resultis the full-surface variant.)
Full-surface exits — live on mainnet since the 2026-06-11 full-surface upgrade (not present in the 25-instruction canary build):
-
auto_accept_task_result— auto-settles a submission to the worker after the review window, so a non-responsive creator cannot strand a completed task. -
close_task— reclaims the terminalTask(+ leftoverTaskJobSpec/ drained escrow / hire link) rent to the creator onceCompletedorCancelled. Refuses to touch an escrow still holding undistributed funds. -
reclaim_completion_bond— permissionless refund of a still-live bond to its poster once the task isCompleted, so a counterparty cannot strand a bond by omitting it during settlement (Batch 3 audit fix). -
expire_dispute— applies the stale assigned-resolver expiry policy and releases escrow; the retired arbiter-vote/quorum path is no longer involved. -
resolve_dispute— settles a dispute to the winning party; bonds of the losing side are forfeited inside this instruction. -
resolve_reject_frozen/expire_reject_frozen— the only exits for aRejectFrozentask; without them its escrow + claim + bonds would strand.
Money-safety substrate, also verified: checked arithmetic on all money paths
(checked_add/sub/mul, ArithmeticOverflow) plus overflow-checks = true
in the release profile (programs/agenc-coordination/Cargo.toml) as a second
layer; fee caps in bytecode (combined ≤ 4000 bps, worker keeps ≥ 60%);
fail-closed moderation; and dispute rulings by either the protocol authority
with configured M-of-N approval or a threshold-seated assigned resolver, with no
per-case arbiter vote/quorum.
The program is upgradeable (BPFLoaderUpgradeable). As of 2026-07-03 the mainnet upgrade authority is a 2-of-3 Squads v4 multisig (migrated from the former single key — P0.3):
Program: HJsZ53Zb27b8QMRbQpuDngE44AdwCGxvEZr61Zmxw1xK
ProgramData: E5w1ZkgC5ysWWBECHHzqsL4s6dDUoyWBnUMRptm5cEAw
Authority: Cj9dWtovMaAsHUkCFqsEeP7GAS86DouqFerh86Qxtnuf (Squads v4 2-of-3 vault)
Multisig: 7VNP3JwLede86xgfG13pzyTKhTiuZkirJPxULrTce5DY (program SQDS4ep65T869…)
(Verify live with solana program show HJsZ53Zb27b8QMRbQpuDngE44AdwCGxvEZr61Zmxw1xK.)
No individual key can now unilaterally push an upgrade — the escrow-custodying
program requires 2-of-3 signatures for any bytecode change. The migration runbook
and full record are in docs/UPGRADE_AUTHORITY.md. The revision-5 upgrade
(deployed 2026-07-22) required a separately reviewed top-level legacy
ExtendProgram action that grew ProgramData by 120,384 bytes.
ProgramData extension is permissionless and does not change executable bytes;
current Agave rejects it through Squads CPI. The pinned rail therefore required
official Agave CLI 4.1.0, snapshotted one private payer keypair inode for address
derivation and execution, and performed two-RPC pre/postflight. Extension
and the separately governed upgrade executed in different slots, and the
deployment rail refuses implicit auto-extension. Residual (tracked, not yet
done): the three member keys are currently co-located on one operator host;
distributing at least one onto separate hardware (a Ledger) is the remaining
hardening — a Squads config change, no program-authority re-transfer required.
The protocol/config authority (which pauses via
update_launch_controls, updates fees, proposes dispute-resolver roster changes, and may propose a direct ruling) is governed by the on-chain multisig inProtocolConfig; each such resolver change or direct ruling requires configured M-of-N approval. It is a distinct concept from the program upgrade authority above. Both are trusted roles; bugs requiring a malicious trusted role are out of scope (§2).
A reproducible / verifiable build (solana-verify, on-chain verification PDA
via osec.io) proves the deployed bytecode matches the source at a public tag.
This repository is public. Revision 5 is now the deployed program (executable
SHA-256 049a66e30da166c1e02ee379993425c32386f774fd9ff8861153e21900b496f2,
deployed 2026-07-22). The prior OtterSec badge
(verify.osec.io/status/HJsZ…)
attested deployed revision 4 at commit 097ded1; re-running the reusable
verifiable build against the revision-5 source is the outstanding follow-up to
re-attest the newly deployed bytecode.
Every protocol-v* release also records a reproducible SHA-256 of the program
built in a pinned Docker image (.github/workflows/verify.yml); reproduce it
with solana-verify verify-from-repo — see docs/VERIFIABLE_BUILDS.md.
Historical note: older drafts of this section described a private-repo gate. That gate is closed; do not reintroduce “repo is private / verify-from-repo unavailable” language without checking the current GitHub visibility and the OtterSec badge.
- Bug bounty scope & rewards:
docs/BUG_BOUNTY.md - Upgrade-authority and capacity runbook:
docs/UPGRADE_AUTHORITY.md - Threat model:
docs/audit/THREAT_MODEL.md - Audit prep / invariants / coverage:
docs/BATCH_1_3_AUDIT_PREP.md - Program surface & PDAs:
docs/PROGRAM_SURFACE.md - Mainnet source of truth:
docs/MAINNET_MAINLINE.md - Local full-surface validator for reproduction:
scripts/localnet-up.mjs(docs/LOCALNET.md) - Machine-readable contact metadata:
.well-known/security.txt(active for the verified GitHub private-advisory channel; both canonical hosted copies must be deployment-verified) - Read-only GitHub, intake, and hosted-schema readiness gate:
docs/ENTERPRISE_READINESS.md
Licensing note: the repository is GPL-3.0 (root LICENSE); the published npm
packages @tetsuo-ai/protocol and @tetsuo-ai/marketplace-sdk are MIT.
Licensing does not change the security commitments above.