Internal implementation security review
This is a source-level review and regression-test record from the implementation team. It is not an independent security audit, penetration test, assurance certification, or approval for mainnet delegation. Review scope: authentication and tenant checks, versioned records, payment review/preparation, database constraints, document storage, API boundaries, deterministic domain controls and the new Solidity contracts.
Corrections made#
| Finding | Correction and boundary |
|---|---|
| A payment review received full configured allowances instead of remaining capacity | Review subtracts settled expenditure and every unresolved allocation from lifetime capacity. Exact last-24-hour source expenditure plus all pending/uncertain allocations consume rolling capacity. Unknown legacy settlement timestamps remain conservative. Previous policy versions do not reset accounting. |
| Different engagements could race against the same policy budget | A shared organization transaction lock precedes engagement/invoice locks and allocation queries. Preparing a payment and inserting its durable allocation occur in one caller-owned transaction. An explicit engagement lock protects obligation allocation. This intentionally serializes treasury writes for correctness. |
| A changed invoice date range created a fresh obligation key | Intake persists obligation identity. Exact billing periods share an identity; differently bounded overlapping invoice periods produce an explicit hold. Editing an existing billing period cannot silently move that identity. This is an ambiguity hold, not a fraud finding. |
| Review silently applied the latest engagement version to an older invoice | Intake pins engagement and destination versions. Review compares those recorded versions with approved current terms. Reusing acceptance after an invoice version change is rejected. A newly reviewed correction is required where the terms no longer match. |
| Vendor address protection did not protect a chain-only change | Generic vendor writes reject changes to either address or chain. Safe identities also cannot be reassigned in place. |
| Destination changes lacked a usable authenticated workflow | Owner proposal and distinct owner/approver confirmation bind the exact vendor version and new destination. Both verify a current database session created within five minutes. A solo exception is visible, requires an explicit reason, proves there is only one eligible workspace member, and requires a second fresh wallet sign-in after the proposal. No browser-supplied reauthenticated flag is trusted. |
| A caller could reuse an idempotency key for a different invoice | Existing keys are bound to the original invoice; a different invoice is rejected. Revalidation may exclude only the current intent for the same invoice and engagement, preserving every other allocation. |
failed could silently free uncertain capacity | Failure releases capacity only with nonblank terminal nonexecution proof and neither a source nor destination transaction. An ambiguous failure or either recorded effect retains capacity. Provider errors are not such proof. |
| A Safe synchronization could be confused with complete history | Bounded chain observations remain incomplete. Owner reconciliation requires tenant-owned supporting documents and exact classification of every observed outgoing transfer. External invoice payments create stable, idempotent observed allocations; unknown transfers keep payment review on hold. Prior-history completeness still depends on the owner's source statements and attestation. |
| Invoice currency was silently coerced to USDC | Invoice and engagement currencies remain explicit. A USD-denominated invoice is not automatically treated as USDC settlement; missing approved conversion remains a hold. |
| Paused delegation also blocked manual preparation | Prepare mode can produce a non-executable human proposal with valid terms, limits and reconciled history. Live Delegate/unpause requires a manifest bound to the exact organization/Safe/chain plus current deployment-bytecode and recorded compatibility/recovery evidence. An environment flag alone does not satisfy this gate. |
Destination, policy and engagement changes mark safe unsubmitted intents invalidated. The worker must reject invalidated authorizations before new submission and atomically check invalidation in its submission state transition. Submitted, uncertain and source-confirmed payments retain their original identity and must continue reconciliation. A database invalidation does not revoke an already signed on-chain permit. Safe owners must pause/revoke or change the on-chain policy epoch when immediate revocation is required; otherwise the prior permit remains subject to its original expiry and on-chain bounds. Capacity is not released merely because an application flag changed.
confirmHistoryReconciliation checks exact observed transfer membership, duplicate log identifiers, tenant document access and recipient/chain/payment matches. It does not establish whether an uploaded statement is truthful, whether a non-payable classification is appropriate, or whether the owner omitted information from earlier history. It records the authenticated human's statement and supporting evidence rather than marketing a boolean as a verified fact. An external transfer matched to an invoice prevents allocating that same paid obligation again; it is never counted as a Countersign-originated transfer.
Regression coverage#
tests/server/security-review.test.ts runs against actual PGlite PostgreSQL storage with both migrations. It covers policy remaining capacity, old pending allocations, source-time rolling windows, ambiguous failed operations, stale invoice/engagement versions, overlapping periods, idempotency binding, current-operation exclusion, explicit currency, tenant and role checks, proposal expiry, fresh two-person/solo destination controls, concurrent preparation across engagements, and exact history matching/idempotent external allocation. Existing authorization and storage tests remain part of verification.
The contract suite separately tests all permit-field binding, caller/signer separation, EIP-1271 verification, replay/installment/obligation limits, midnight rolling-window bursts, policy changes, independent Safe administration, cash floors, collateral exhaustion, claimed-liability retention, payout recovery deduction, and restricted CCTP call/rollback behavior. Stateful invariants verify payment-effect accounting and reserve conservation. Local mocks are not evidence of compatibility with a specific deployed Safe or Circle wallet.
Residual release requirements#
The 6 October expansion also rechecks exact current membership after acquiring the organization mutation lock, preserves acceptance across settlement bookkeeping while invalidating material corrections, binds partial retries to the same amount, and reserves shared-Safe capacity across policies. Operations case resolution only requests a new review; it cannot clear a financial hold or authorize payment. Notification reservations are persisted before contacting the provider, and unknown outcomes are never blindly retried. Regression tests cover these controls and complete-source proposal-only extraction.
Dependency audit, 6 October 2026#
Next.js and its ESLint config are pinned to 16.3.8. The fixable source-map-js advisory was remediated to 1.2.2. npm audit --omit=dev reports zero production dependency findings at this revision.
The full audit still reports five high-severity package entries arising from one unpatched braces stack-exhaustion advisory: braces → micromatch → fast-glob → Next's ESLint plugin/config. This is a development dependency chain. At that release the worker templates installed development dependencies for their TypeScript launcher; the 13 October packaging revision removes that chain from final worker images. No worker/application input path to this glob chain was found in the scoped review. The plugin calls fast-glob for an explicitly configured settings.next.rootDir pattern; the checked-in ESLint configuration does not supply that setting. This reachability assessment is scoped to this source/configuration; it does not erase the development advisory or make arbitrary untrusted development glob input safe. Reassess if lint configuration changes and adopt an upstream fix when available. A framework downgrade is not used to make the audit count disappear.
Worker dependency review, 13 October 2026#
Final worker images now install only dedicated lockfiles and bundled worker entrypoints. They exclude Next.js, React, the TypeScript launcher/compiler, lint/test tooling and the vulnerable development glob chain. The common PostgreSQL/validation/chain runtime reports zero production npm findings. Circle CLI 1.1.4 is installed only in the financial image, with production dependencies locked independently and compiler-only peer dependencies omitted. No profiles, secrets, originals or private workspace files enter either image.
Exact transitive updates to jayson 5.0.0, toml 5.0.0 and 8.x ws 8.22.0 remove the reported fixable JSON streaming/UUID/TOML/WebSocket advisories. These override the upstream dependency ranges; CLI import/help and exact execute/lookup/reconciliation flag checks verify the local command interface. They do not establish Solana/Anchor behavior, compatibility with a real Circle account, contract execution, or independent recovery. Countersign still requires its deployment-specific compatibility/review evidence.
The financial CLI production audit retains nine package entries from two unpatched advisory roots: two high entries from `node-forge` RSA verification through the CLI, and seven low entries from `elliptic` primitive risk through the ethers dependency chain. The inspected node-forge 1.4.0 and elliptic 6.6.1 releases have no patched successor for these findings. Circle CLI 1.2.1 retains the same forge and ethers dependency paths, so that version upgrade does not resolve this gate.
A fresh 13 October registry/advisory check confirms Circle CLI's latest published version is 1.2.1, published 9 October, retaining node-forge:^1.3.1 and @ethersproject/abi:5.8.0. Both linked advisories still list no patched version. A fresh npm audit --prefix worker-runtime/circle --omit=dev --omit=peer reproduces two high and seven low entries with no available fix. The locked 1.1.4 adapter interface is retained; changing the CLI version alone cannot close this gate. Provider remediation or a separately reviewed supported integration is required before financial activation.
In the inspected CLI 1.1.4 entrypoint, forge calls perform hashing, DER envelope parsing and RSA-OAEP encryption; no forge RSA signature-verification call was found. The reported forge issue affects PKCS#1 v1.5 signature verification. This is a scoped source-path review, not proof of universal non-reachability or permission to waive the advisory. The ethers chain remains physically present. Do not apply a homemade cryptographic patch or substitute an unreviewed signer to erase an audit count.
Fresh supported-repair and runtime-path check#
Rechecked against the 0.4.0 cb14acc baseline on 13 October. An isolated lock-only installation of CLI 1.2.1, using the existing compatible transitive overrides, resolves node-forge 1.4.0 and elliptic 6.6.1 and still reports two high and seven low findings, all with fixAvailable:false. The Forge registry and Elliptic registry list no newer published patched or prerelease tag. The proposed Forge repair PR 1152 remains open; downstream references marked merged are not an upstream release. Installing an unmerged PR, renaming its package version or carrying a local cryptographic patch is not a supported dependency update.
| Advisory root | Exact installed path and scoped runtime exposure |
|---|---|
High: node-forge RSA verification | @circle-fin/cli@1.1.4 → node-forge@1.4.0. Agent wallet execute calls handleAgentExecute → runTransactionChallenge → executeChallenge → CircleSdkClient.executeChallenge. Challenge approval reaches Forge SHA-256 hashing and RSA-OAEP public-key encryption through deriveSocialPin and encryptPinHash; OTP envelope parsing also imports Forge. The package is therefore used in the financial authentication path. The inspected functions do not call the advisory's vulnerable PKCS#1 v1.5 signature-verification primitive. That narrower observation is not an assurance over every provider response or future SDK path. |
Low: elliptic ECDSA primitive risk | @circle-fin/cli → @ethersproject/abi@5.8.0 → @ethersproject/hash → @ethersproject/abstract-signer → @ethersproject/abstract-provider → @ethersproject/transactions → @ethersproject/signing-key → elliptic@6.6.1. The CLI imports the ABI package at startup. SigningKey.signDigest in that dependency calls Elliptic signing with a secp256k1 curve and a required 32-byte digest, but no call to that generator was found in the inspected bounded agent-wallet execution handler, which delegates approval to Circle's MPC challenge flow. Countersign rejects local-wallet fallback. The dependency remains installed and loadable; curve-specific advisory applicability and the complete provider flow still need independent review. This source inspection cannot prove universal non-reachability, establish key compromise or remove the reported signature/key-exposure risk. |
`@ethersproject/signing-key` 5.8.0 is the latest release of that package and pins Elliptic 6.6.1. The separately named ethers 6.x API is not a compatible version of the CLI's pinned @ethersproject/* 5.x modules; migrating the vendor to it requires a supported vendor integration and renewed tests/review. No narrow supported update currently eliminates these roots. The strict audit continues to fail. A human review does not make the audit clean, publish an upstream fix or authorize a hidden exception. Resolve the provider gate with a supported reviewed release/integration, then verify the exact authenticated execution, profile/session renewal, timeout and independent recovery path before activation.
The Worker containers workflow has independent build/smoke and runtime-audit jobs. The latter deliberately fails on moderate/high provider findings without continue-on-error, filtering or an allowlist. Build/smoke evidence can be collected while the financial dependency gate remains blocked. Keep financial execution disabled until a reviewed provider fix or independently reviewed alternative resolves this gate. The operations-only worker has no Circle dependency and can be evaluated separately with notices disabled. Docker was unavailable locally; inspect the exact hosted CI run before asserting image-build success.
Execution evidence and Arc observations, 13 October 2026#
Cached deployment evidence is checked again before and after chain verification, after module authority readback, and immediately before the Circle execution command after wallet discovery. An expired or future-dated review cannot enable a new submission. Worker startup can load expired identity evidence explicitly for reconciliation; submitted and uncertain operations retain their original identities and reserved capacity. This read-only reconciliation purpose does not satisfy the strict authorization, preflight or execution gates. Expiry also cannot cancel an already issued on-chain permit or an in-flight provider operation; use Safe owner revocation for that authority boundary.
Arc's canonical USDC system-event reference documents separate native 18-decimal and ERC20 6-decimal event streams. ERC20-only observation misses plain native USDC sends. The Arc USDC observer now selects the canonical system emitter, preserving each original native amount while conservatively rounding outgoing liabilities up and incoming funds down into ERC20 principal units. It does not count the duplicate ERC20 event. Fractional outgoing amounts cannot automatically match a rounded payment principal; incremental reconciliation holds for human review. Removed, malformed or out-of-window logs are rejected. Pre-Zero5 testnet windows are explicitly rejected pending independent historical reconciliation, using the official activation reference.
Each independently confirmed operation may match only one outgoing effect during incremental reconciliation; a second matching log holds the observation instead of reusing the same operation proof. The scan remains bounded and initial statements require an owner-backed baseline. Arc EVM differences explain that gas deductions emit no transfer log and the ERC20 balance truncates native precision. Fee and native-balance statements remain necessary for full accounting. Fixture tests prove observation and hold behavior; they do not establish live RPC completeness, Safe compatibility or a genuine settlement. See contracts for the remaining deployment and SCA relay evidence requirements.
Residual operational review#
- Independently review the application, verifier, contracts, deployment composition and operational key policy before broad real-money delegation. Resolve critical findings and retain the reviewed commit and deployment manifest.
- Prove the real Circle agent wallet/module call path and revocation behavior. Successful transaction hashes and code hashes are evidence references; their semantic interpretation requires review. No operator EOA substitution is permitted while claiming Circle-backed execution.
- Validate actual source/destination token deployments, decimals, finality and fee behavior. The CCTP contract's amount is the gross source debit; recipient delivery and invoice reconciliation must use actual net delivery. Source burn alone is not a paid invoice.
- Protect verifier and Circle credentials separately; production signer isolation and customer-specific credential administration remain operational requirements. A compromised verifier plus available executor authority can issue false business attestations within owner-installed limits.
- Protect database credentials. RLS is enabled and no public data policies are granted; server code uses tenant predicates. The server/database-owner role is privileged and can bypass RLS, so SQL authorization is a critical application boundary, not a substitute for least-privilege deployment.
- Supply encrypted-document key backup/rotation and recovery procedures. Documents use AES-GCM with organization-bound associated data and randomized commitments. Losing the encryption key loses document availability. Uploaded evidence remains untrusted; authentication does not prove document truth.
- Provision independent reserve reviewer authority, accepted terms, adequate funding and a reviewer recovery procedure before advertising protection. Contracts have no unilateral operator escape that can impair open liabilities. Final claim resolution is final on-chain; an appeal process must precede that final action.
- Preserve independent Safe owner access. The module cannot prevent owners/other modules from making outside transfers, cannot protect invisible liabilities or native gas costs, and cannot reverse completed payments. Application outages must not lock human treasury control.
The API review also identified deployment-facing input-resource and spreadsheet-export concerns: request bodies should be bounded while streaming, document uploads must fit the host's request limit, CSV formula defenses must include leading control/whitespace prefixes, and sign-in challenge issuance should have an additional abuse budget beyond the claimed wallet address. These are now enforced in the application: streaming byte limits, a 4 MB document cap, whitespace/control-aware CSV escaping, and a global challenge budget in addition to per-wallet budgets. Hosting-level abuse protection and production monitoring still require operational configuration.
Run npm test -- tests/server/security-review.test.ts and the complete repository verification command before release. This report describes implementation controls and remaining responsibilities; it is not a claim of audited safety or genuine customer usage.