Skip to content

fix(security): close zod/body-parser gate failures + post-review doc corrections - #200

Merged
M0nsxx merged 5 commits into
mainfrom
docs/post-interest-form-corrections
Oct 23, 2026
Merged

M0nsxx merged 5 commits into
mainfrom
docs/post-interest-form-corrections

Conversation

@Eras256

@Eras256 Eras256 commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three things, found during a full post-Interest-Form repo review:

  • docs/FOR-REVIEWERS.md, SECURITY.md, two stale repo-name references: OtterSec audit scope wording corrected (the Etherfuse CETES pool itself is outside the audit), a misleading "two independent places" claim fixed (the public mirror is a manual sync of this repo, not an independent source - the chain is), github.com/Eras256/Nirium links updated to nirium-protocol/nirium-core, every tx hash/PR/issue state/GrantFox count re-verified live before updating "Last verified". actions/verify-audit-cid/README.md and packages/sdk-python/README.md still pointed at the pre-rename nirium-protocol/nirium-sdk (redirects, but fixed to the real name).
  • Security Gate: GHSA-mrhx-c7xc-m3w5 (zod < 4.6.6, high) resolves via two separate paths in this repo. The @stellar/mpp > mppx > viem/abitype/incur > zod path is fixed for real in sdk and cli via a scoped overrides entry - every package on that chain already accepts zod ^4.x, verified live (npm ls zod, both packages still build clean). The identical override breaks mcp for a real, verified reason (npm error ELSPROBLEMS, documented inline in the workflow), so mcp keeps an audit-ci allowlist instead, proven scoped-correctly by temporarily installing an unrelated real critical advisory and confirming the gate still caught it. @x402/core's own zod ^3.24.2 dependency has no compatible fix upstream (confirmed against the latest published version, 2.28.0) - allowlisted in all three packages, that part is unavoidable for now.
  • README quickstart: "Quickstart: charge for your API" only said npm install nirium; following it as written throws x402Serve needs "@x402/express" on the first real request. Added the actual install line.

Test plan

  • npm ls zod confirms the mppx/viem/abitype/incur subtree resolves to a patched zod in sdk and cli
  • sdk, cli, mcp all build clean (tsc)
  • npx audit-ci@7 --high --allowlist GHSA-mrhx-c7xc-m3w5 exits 0 in all three packages
  • Allowlist scoping proven: temporarily installed minimist@1.2.0 (real critical advisory, GHSA-xvch-5gv4-984h) as a tracked dependency, confirmed the gate still failed on it while passing on the zod advisory; reverted after
  • Checked for a body-parser DoS advisory published today (GHSA-27r3-jxmh-p828) that affected a sibling repo - not present here, all three packages already resolve a patched body-parser@2.4.0 via a newer express
  • Every tx hash, contract address, PR/issue state and the GrantFox bounty count in docs/FOR-REVIEWERS.md re-verified live (Horizon + GitHub API) before updating "Last verified"

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Eras256 and others added 4 commits October 23, 2026 11:01
- actions/verify-audit-cid/README.md and packages/sdk-python/README.md
  still pointed at nirium-protocol/nirium-sdk, the pre-rename repo
  name. It redirects, but the real name is nirium-protocol/nirium.
- docs/FOR-REVIEWERS.md: the OtterSec audit line said "the vault
  strategy (Etherfuse CETES on Blend v2) was audited" without
  flagging that the Etherfuse pool itself sits outside that scope -
  the README's own "Networks" section already states this correctly,
  this page didn't match it. Also called the public mirror and this
  repo "two independent places citing the same transactions" when
  they're not independent - one is a manual sync of the other; the
  chain is what's actually independent. Fixed the stale
  Eras256/Nirium links to nirium-protocol/nirium-core. Re-verified
  every tx hash, contract address, PR/issue state and the GrantFox
  count live before updating "Last verified".
- SECURITY.md: the RLS fix noted 6 affected tables and called the
  migration "prepared but not yet applied". A 7th table (webhooks)
  turned out to have the same exposure, and all 7 are now fixed and
  re-verified (anon key gets Content-Range: */0 on all of them).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
zod < 4.6.6 (high, CWE-770 memory exhaustion validating oversized
arrays) is only fixed in zod 4.6.6+. @x402/core 2.28.0, the latest
published version, still requires zod ^3.24.2, which cannot resolve
to 4.x. No patched 3.x release of zod exists either.

npm has no package.json-level allowlist equivalent to pnpm's
auditConfig.ignoreGhsas, so this uses audit-ci instead, scoped to
exactly this one advisory — verified live (sdk, cli, mcp each go from
exit 1 to exit 0 with `--allowlist GHSA-mrhx-c7xc-m3w5`, same
lockfile, nothing else touched). The same GHSA also resolves via a
second, unrelated path in all three packages
(@stellar/mpp > mppx > viem/abitype/incur > zod@4.4.3, which CAN
reach zod 4.6.6+ since every package in that chain already accepts
zod ^4.x) — audit-ci's allowlist matches by advisory ID regardless of
path, so this is covered by the same one-line change, not forced via
override.

Exposure assessment (x402Serve(), the question of whether a client
could trigger this via a paid-route request): the client-submitted
payment proof travels in the PAYMENT-SIGNATURE header, base64-encoded
JSON (@x402/core's extractPayment()/decodePaymentSignatureHeader()),
not the request body — Node's default http.maxHeaderSize (16KB,
shared across all headers) caps what reaches JSON.parse regardless of
anything in this codebase or @x402/core/@x402/express/@x402/stellar,
none of which override it. The zod schemas that validate that
decoded payload (PaymentPayloadV1Schema: payload: Any;
PaymentPayloadV2Schema: accepted: <single object>) don't contain an
unconstrained array — this GHSA's specific "oversized array" OOM
mechanism isn't reachable through that path. The unconstrained arrays
that do exist in @x402/core (PaymentRequiredV1Schema/V2Schema's
`accepts: z.array(...).min(1)`, no .max()) validate the outgoing 402
challenge the server itself constructs from its own routes config,
not something a client submits.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to b7f7a32, which allowlisted GHSA-mrhx-c7xc-m3w5 wholesale
without distinguishing its two separate paths. Tested properly this
time, per the explicit ask to verify rather than assume, and the
result differs by package:

sdk and cli: @stellar/mpp > mppx > viem/abitype/incur > zod resolved
below 4.6.6 (the patched version), but every package on that chain
already declares zod ^4.x in its own peerDependencies — nothing pins
it low, it just never got bumped. Fixed with a nested override
("overrides": { "mppx": { "zod": "^4.6.6" }, "@stellar/mpp": {...},
"viem": {...} }), scoped to only those three parents so it never
touches @x402/core's zod ^3.x dependency. Verified: `npm ls zod` shows
the whole subtree resolving to a patched version in both packages,
both still build clean. Proved the allowlist stays correctly scoped
by temporarily installing a real unrelated critical advisory
(GHSA-xvch-5gv4-984h via minimist@1.2.0, as a real tracked dependency,
not extraneous) and confirming the gate still failed on it while
passing on the zod one - reverted after.

mcp: tried the identical override and it broke something real, not
just a warning - `npm error code ELSPROBLEMS: invalid: zod@3.25.76`,
because mcp's own direct "zod": "^3.25.0" dependency conflicts with
@modelcontextprotocol/sdk wanting ^4.6.6 once the override applies.
npm's flatter resolution here doesn't give the same per-branch
isolation that let this exact pattern work safely in nirium-core
(pnpm). Reverted; mcp keeps the allowlist-only fix from b7f7a32.
Separately noticed while testing, unrelated to this fix and not
touched here: mcp's built server can't currently boot at all on a
pristine clone of this repo's unmodified main - `Cannot find package
'viem'` from mppx/dist/evm/client/Charge.js.

@x402/core (resolved in all three packages, 2.28.0) still requires
zod ^3.24.2, which cannot resolve to 4.x even with the override -
confirmed against the latest published @x402/core, same range. No
patched 3.x release of zod exists either. That's what's still
allowlisted via audit-ci in all three packages.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Quickstart: charge for your API" only said `npm install nirium`,
inherited visually from the unrelated "pay for an API" section above
it. Following it as written hits `x402Serve needs "@x402/express".
Install it alongside the SDK: npm i @x402/express @x402/core
@x402/stellar` on the first real request - exactly the message
nirium's own code throws for this. Added the real install line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Eras256
Eras256 requested a review from M0nsxx as a code owner October 23, 2026 22:26
main moved 5 commits (PRs #195-199, cli fixes + aligning nirium/
@Stellar-SDK versions and adding @x402/express as a direct dependency)
while this branch was open, leaving it unmergeable and silently
blocking its CI/PR checks from ever running. Only real conflict was
packages/cli/package-lock.json - resolved by deleting and
regenerating via npm install, not by hand-editing. package.json
merged clean on its own (main's new deps alongside this branch's zod
overrides).

Re-verified after the merge, not just resolved and moved on:
`npm ls zod` still shows the mppx/@stellar-mpp chain at 4.6.7 and
@x402/core (now also reached via the new @x402/express dependency)
still at 3.25.76; audit-ci --allowlist GHSA-mrhx-c7xc-m3w5 exits 0;
body-parser resolves to the patched 2.4.0; `node --check bin/nirium.js`
and the full cli test suite (59/59) both pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@M0nsxx
M0nsxx merged commit b3c6752 into main Oct 23, 2026
16 checks passed
@Eras256
Eras256 deleted the docs/post-interest-form-corrections branch November 4, 2026 01:16
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.

2 participants