Skip to content

fix(security): correct RPC simulation shape, warn on secrets, label admin examples - #142

Open
habnark wants to merge 2 commits into
Axionvera:mainfrom
habnark:security/66-examples-and-rpc-audit
Open

fix(security): correct RPC simulation shape, warn on secrets, label admin examples#142
habnark wants to merge 2 commits into
Axionvera:mainfrom
habnark:security/66-examples-and-rpc-audit

Conversation

@habnark

@habnark habnark commented Jul 29, 2026

Copy link
Copy Markdown

Description

Security audit of SDK examples per issue #66: reviewed README, docs, and
examples/migration/ for unsafe key handling, admin misuse, incorrect RPC
formatting, and compliance claims.

What changed:

  • RPC formatting (the real find): ComplianceModule.checkWhitelist and
    InvestorModule's balance lookup both called simulateTransaction({ transaction: call as any } as any) — a { transaction } wrapper around an
    unbuilt contract-call operation. rpc.Server.simulateTransaction actually
    takes a built Transaction directly as its first argument. Both were wrong
    on two counts (wrapper shape + unbuilt operation), papered over with as any. Fixed via a new shared helper, src/utils/simulation.ts, used by both
    call sites; added regression tests asserting the real Transaction shape.
    Also corrected the same pattern everywhere it was copy-pasted into
    examples/migration/*.ts and docs/migration-guide.md's "before" snippets.
  • Unsafe secret handling: every Keypair.fromSecret('S...') in
    README.md, docs/migration-guide.md, and
    examples/migration/mint-transfer-before-after.ts now loads from
    process.env.AEGIS_ISSUER_SECRET! with an explicit "never hardcode a real
    secret" warning comment next to it, instead of showing a bare string
    literal as the pattern to copy.
  • Admin examples labelled: the README Quickstart no longer constructs an
    unused, misleadingly-named adminKeypair for what is actually a read-only
    call (checkWhitelist needs no signer). A new "Privileged Operations
    (Admin / Issuer)" README section, and ⚠️ labels on the Minting/Transferring
    sections of docs/migration-guide.md, now clearly mark where a privileged
    signer is actually required.
  • Compliance limitations: reviewed docs/api-reference.md,
    docs/role-discovery.md, docs/contract-events.md, and
    docs/admin-action-receipts.md — all already carry accurate
    protocol-vs-legal compliance disclaimers. No gap found; no changes needed
    here beyond updating the one stale "Open note" in api-reference.md that
    described the now-fixed as any uncertainty.
  • Security checklist references examples: docs/reviewer-checklist.md's
    Security section now explicitly requires the secret-loading pattern,
    admin-labelling convention, and correct simulateTransaction shape shown
    above, and names the audited files as the canonical reference.

Why this approach: the secret/admin issues were fixable as documentation
changes, but the RPC formatting issue turned out to be a real bug in
production src/ code (not just examples) once traced back to its source —
fixing it there and reusing one helper across both call sites was the
correct fix, not just adding a caveat comment.

Closes: #66


Evidence Checklist

1. Issue Reference

  • This PR references a tracked issue (Closes #66).
  • The linked issue's acceptance criteria are copied into Section 6 below.

2. Implementation Summary

  • Summary above.
  • Rationale above.
  • Files changed:
    • src/compliance.ts, src/investor/portfolio.ts — use the new shared simulation-transaction builder instead of the wrapper-object pattern.
    • src/utils/simulation.ts (new) — shared buildSimulationTransaction helper.
    • tests/compliance.test.ts (new) — first direct unit tests for ComplianceModule, including the RPC-shape regression test.
    • tests/investor.test.ts — added a regression test for the balance-lookup RPC shape.
    • README.md, docs/migration-guide.md, docs/api-reference.md, docs/reviewer-checklist.md — secret-handling warnings, admin labelling, updated open note, checklist references.
    • examples/migration/*.ts (4 files) — corrected RPC shape in "before" snippets, secret-handling warning in the mint/transfer "after" snippet.

3. Tests

  • New/updated unit tests cover the changed public behaviour (checkWhitelist, portfolio balance lookup).
  • docs//examples/ changes are documentation-only; no runtime tests apply to them beyond the src/ regression tests above, which exercise the same code path the examples demonstrate.

4. Commands Run

$ npm run build
> @aegis/sdk@0.1.0 build
> tsc
(no output — clean compile)

$ npm test
Test Suites: 11 passed, 11 total
Tests:       90 passed, 90 total
Time:        35.453 s

$ npm run test:compat
Browser compatibility: bundle resolved without Node-only imports.
Node compatibility: public SDK entrypoint and signer initialized.

$ npm run check   # build + test --runInBand + test:compat
(all three steps passed — see full output below)
Command output
> @aegis/sdk@0.1.0 build
> tsc

> @aegis/sdk@0.1.0 test
> jest --runInBand

PASS tests/investor.test.ts (16.546 s)
PASS tests/role.test.ts
PASS tests/mock-client.test.ts
PASS tests/events-decoder.test.ts
PASS tests/mock-client-examples.test.ts
PASS tests/events-module.test.ts
PASS tests/network-failures.test.ts
PASS tests/client.test.ts
PASS tests/compliance.test.ts
PASS tests/admin-receipts.test.ts
PASS tests/config.test.ts

Test Suites: 11 passed, 11 total
Tests:       90 passed, 90 total
Snapshots:   0 total
Time:        35.453 s, estimated 83 s

> @aegis/sdk@0.1.0 test:compat
> node scripts/check-compat.mjs

Browser compatibility: bundle resolved without Node-only imports.
Node compatibility: public SDK entrypoint and signer initialized.

5. CI Status

  • All GitHub Actions checks pass on this PR. (Not yet observed — will confirm once CI runs.)
  • If a CI step failed, a root-cause explanation is provided below.
CI failure notes

npm run lint fails on this branch, but it also fails identically on main
before this PR's changes: eslint is referenced by the lint script but is
not installed as a dependency, and no eslint.config.js exists in the repo.
This is a pre-existing repository gap, not something introduced by this PR —
npm run build, npm test, and npm run test:compat all pass cleanly.

6. Acceptance Criteria Coverage — Traceability Table

# Acceptance Criterion SDK Module(s) Test(s) Doc(s) Behaviour Verification
1 Examples are reviewed. README.md, docs/migration-guide.md, examples/migration/*.ts (4 files) All four migration examples and both README code samples read end-to-end; findings below.
2 Unsafe secret handling is removed or clearly warned. README.md, docs/migration-guide.md, examples/migration/mint-transfer-before-after.ts Every Keypair.fromSecret(...) now reads from process.env.AEGIS_ISSUER_SECRET! with an adjacent "never hardcode a real secret" comment; no bare 'S...' literal remains as the pattern to copy.
3 Admin examples are labelled. README.md (Privileged Operations (Admin / Issuer) section), docs/migration-guide.md (Minting/Transferring/Setup sections) Each privileged example carries a ⚠️ Privileged operation note; the read-only Quickstart no longer includes an unused signer.
4 RPC formatting is corrected. src/compliance.ts, src/investor/portfolio.ts, src/utils/simulation.ts tests/compliance.test.ts (calls simulateTransaction with a real built Transaction, not a wrapper object), tests/investor.test.ts (calls simulateTransaction with a real built Transaction for the balance query) simulateTransaction now receives a built Transaction instance directly; tests assert passedArg instanceof Transaction and the correct networkPassphrase, replacing the old { transaction: call as any } as any shape.
5 Compliance limitations are stated. docs/api-reference.md, docs/role-discovery.md, docs/contract-events.md Reviewed; existing protocol-vs-legal disclaimers already present and accurate. Updated the one stale "Open note" in api-reference.md that described the now-fixed RPC-shape uncertainty.
6 Security checklist references examples. docs/reviewer-checklist.md Security section (§5) now lists the secret-loading pattern, admin-labelling convention, and correct RPC shape as explicit review items, and names the audited files.

Reviewer Notes

The RPC-formatting fix (#4) is the substantive change here — it's a real bug
in src/, not just a documentation issue, found while tracing why the
migration examples' "before" snippets used a pattern that looked fragile.
ComplianceModule previously had no direct unit tests at all (only exercised
indirectly via InvestorModule and mocked away in role.test.ts), which is
likely why this went unnoticed; tests/compliance.test.ts closes that gap.

habnark and others added 2 commits July 29, 2026 12:54
…dmin examples

checkWhitelist and the portfolio balance lookup called simulateTransaction
with a raw contract-call operation wrapped in `{ transaction: ... } as any`,
rather than a built Transaction. rpc.Server.simulateTransaction expects a
Transaction directly; both call sites are fixed via a shared
buildSimulationTransaction helper, with regression tests asserting the real
Transaction shape now used.

Also removes the unnecessary signing keypair from the README's read-only
Quickstart (it was labeled "adminKeypair" for a call that needs no signer),
adds an explicit Privileged Operations section for mint/transfer, and
replaces every hardcoded Keypair.fromSecret('S...') in README/docs/examples
with an env-var pattern plus a "never hardcode a real secret" warning.
Updates the reviewer checklist's security section to reference these
examples so future ones are held to the same bar.

Closes #66
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant