Skip to content

fix(gateway): only the kernel's operator may create a shared batch on it (N55) - #497

Closed
LamaSu wants to merge 1 commit into
masterfrom
fix/n55-shared-batch-kernel-operator
Closed

LamaSu wants to merge 1 commit into
masterfrom
fix/n55-shared-batch-kernel-operator

Conversation

@LamaSu

@LamaSu LamaSu commented Oct 3, 2026

Copy link
Copy Markdown
Owner

N55: only a kernel's operator may create a shared batch on it

The hole (live on master 7d688ce). POST /api/batches/shared checked no identity. Any authenticated key could publish a priced shared batch (slots and price per slot) under another operator's kernel. Buyers claiming its slots would believe that operator made the offer.

The fix is the kernel-operator check from routes/lob.ts and routes/carrier.ts:

  • No caller (req.operatorId ?? req.userId, trimmed): 401 unauthenticated.
  • Unknown kernel: 404 kernel_not_found (502 kernel_lookup_failed if the lookup itself fails).
  • A kernel with no operator, or the zero address: 403 kernel_unowned.
  • A caller who isn't the kernel's operator (compared case-insensitively): 403 not_kernel_operator.

Tests: shared-batch-owner.test.ts, 8 tests. 5 fail on master: the stranger, unknown-kernel, zero-operator, no-identity and blank-identity cases all got 200. Gateway tsc is clean. The full gateway suite has 3714 passed, 13 skipped and 1 failure, in negotiation-settlement-correctness.test.ts. That test passes alone 3 times out of 3, both with this change and with master's batches.ts, so it's a full-run flake and not this change.

Merge order: this is an ownership guard, so it merges after WP-A (#326) under rule 6. #375 (N49) rewrites the same file, so whichever merges second takes a small rebase. Both PRs are refvertical's.

Callers: the dashboard's BatchBoardPage creates shared batches with the signed-in user's key. After this change only the kernel's operator can create one on that kernel, which is the intent.

Board row N55 (refvertical).

🤖 Generated with Claude Code

https://claude.ai/code/session_01KBTXKQ2uqtcrsUtPnQdtf8

… it (N55)

POST /api/batches/shared checked no identity. Any authenticated key could
publish a priced shared batch (its slots and its price per slot) under another
operator's kernel, so buyers claiming those slots would believe that operator
had made the offer. A shared batch is the kernel operator's offer, so the route
now applies the kernel-operator check that routes/lob.ts and routes/carrier.ts
use:

- no caller (req.operatorId ?? req.userId, trimmed): 401 unauthenticated;
- an unknown kernel: 404 kernel_not_found (502 kernel_lookup_failed if the
  lookup itself fails);
- a kernel with no operator, or the zero address: 403 kernel_unowned;
- a caller who is not the kernel's operator (compared case-insensitively): 403
  not_kernel_operator.

Tests: shared-batch-owner.test.ts has 8 tests. Five fail on master 7d688ce,
where a stranger, an unknown kernel, a zero-operator kernel, no identity and a
blank identity all got 200. All 8 pass now.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBTXKQ2uqtcrsUtPnQdtf8
@LamaSu

LamaSu commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

Closing this in favour of #403 (readmodels), by agreement with the steward (bus #5435/#5438) and readmodels (#5227/#5436).

The cross-family review of this PR found the route check fails closed, but the identity it trusts (req.operatorId) can be self-provisioned: public POST /api/auth/provision mints a key for any wallet address without a SIWE proof. #403 gates the same POST /api/batches/shared on WP-A's SIWE-proven wallet (precheckJobRead / kernelScopeOf), and also gates the claim, slots and release routes. So board row N55 is covered by #403, which merges after WP-A (#326).

🤖 Generated with Claude Code

https://claude.ai/code/session_01KBTXKQ2uqtcrsUtPnQdtf8

@LamaSu LamaSu closed this Oct 3, 2026
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