This release includes 1 security fix for security teams reviewing exposed deployments.
Topics
+3 more
Affected surfaces
ReleasePort's take
Light signalGuest authentication now returns a 401 for invalid bearer tokens instead of falling back to anonymous access.
Why it matters: Patch immediately if your environment relies on token‑based guest auth; the change prevents unintended privilege escalation when tokens are malformed.
Summary
AI summaryInvalid guest bearer tokens now return 401 instead of downgrading to anonymous access.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Medium |
Guest auth now returns 401 for invalid bearer tokens instead of anonymous downgrade. Guest auth now returns 401 for invalid bearer tokens instead of anonymous downgrade. Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Security | Medium |
Security review gate (G1–G5 evidence) introduced for v0.12.1 release planning. Security review gate (G1–G5 evidence) introduced for v0.12.1 release planning. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Breaking | Medium |
Inspector build prepublish now exits non-zero if inspector submodule is missing, breaking ad-hoc npm pack runs without init. Inspector build prepublish now exits non-zero if inspector submodule is missing, breaking ad-hoc npm pack runs without init. Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Feature | Medium |
Codex / OpenAI function-tool compatibility restored by removing top-level anyOf from submit_issue, add_issue_message, get_issue_status schemas. Codex / OpenAI function-tool compatibility restored by removing top-level anyOf from submit_issue, add_issue_message, get_issue_status schemas. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Operator hardening knobs (NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN, NEOTOMA_GUEST_TOKEN_TTL_SECONDS, NEOTOMA_HOSTED_MODE, MCP_PROXY_FAIL_CLOSED) now documented in SECURITY.md and docs/security/threat_model.md. Operator hardening knobs (NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN, NEOTOMA_GUEST_TOKEN_TTL_SECONDS, NEOTOMA_HOSTED_MODE, MCP_PROXY_FAIL_CLOSED) now documented in SECURITY.md and docs/security/threat_model.md. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
neotoma doctor --json spec documented with risk codes, suggested safe data dir, migration command, and tool override. neotoma doctor --json spec documented with risk codes, suggested safe data dir, migration command, and tool override. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
reload_neotoma_launchagents.sh --kill-zombies documented for orphan process cleanup. reload_neotoma_launchagents.sh --kill-zombies documented for orphan process cleanup. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
bulk_close_issues and bulk_remove_issues tools added to MCP_SPEC.md spec table with HTTP equivalents. bulk_close_issues and bulk_remove_issues tools added to MCP_SPEC.md spec table with HTTP equivalents. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
store request fields observation_source, source_peer_id, external_actor documented in MCP_SPEC.md with reducer semantics. store request fields observation_source, source_peer_id, external_actor documented in MCP_SPEC.md with reducer semantics. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Four new operator-facing site pages added: /peer-sync, /subscriptions, /issue-reporting, and /security-hardening. Four new operator-facing site pages added: /peer-sync, /subscriptions, /issue-reporting, and /security-hardening. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Feature | Medium |
Release skill workflow adds hard gate before Step 4 requiring explicit G1/G2/G3/G4 evidence and populated security_review.md. Release skill workflow adds hard gate before Step 4 requiring explicit G1/G2/G3/G4 evidence and populated security_review.md. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Performance | Medium |
Inspector packaging now fails closed when inspector submodule is missing, preventing silent omission of bundled Inspector. Inspector packaging now fails closed when inspector submodule is missing, preventing silent omission of bundled Inspector. Source: llm_adapter@2026-05-21 Confidence: high |
— |
| Deprecation | Medium |
Removed top-level anyOf combinator from MCP tool schemas; server-side enforcement unchanged. Removed top-level anyOf combinator from MCP tool schemas; server-side enforcement unchanged. Source: llm_adapter@2026-05-21 Confidence: low |
— |
| Refactor | Medium |
Removed legacy /subscriptions/sse shorthand reference, aligning with new GET /events/stream SSE path. Removed legacy /subscriptions/sse shorthand reference, aligning with new GET /events/stream SSE path. Source: llm_adapter@2026-05-21 Confidence: low |
— |
Full changelog
Install
npm install -g [email protected]
| | |
|:--|:--|
| npm | https://www.npmjs.com/package/neotoma/v/0.12.1 |
| Compare | v0.12.0 → v0.12.1 — view diff |
v0.12.1 hardens the v0.12.0 surface area without changing its shape. It closes a guest-token validation gap on the auth path, restores Codex / OpenAI function-tool compatibility for the issue MCP tools (server-side enforcement is unchanged), tightens the prepublish Inspector build, and ships the operator-facing v0.12 documentation that the v0.12.0 tag advertised but did not yet include — a Doctor CLI reference, the operator hardening knobs, the LaunchAgent zombie-cleanup flag, the documented bulk_close_issues / bulk_remove_issues tools, and dedicated site pages for peer sync, substrate subscriptions, issue reporting, and security hardening.
Highlights
- Guest auth: invalid bearer tokens no longer downgrade to anonymous.
maybeStampGuestPrincipalis now async and explicitly validates anAuthorization: Bearer …guest access token againstvalidateGuestAccessTokenbefore stamping the request principal. Guest-scoped entity reads also re-assert the token via a newassertValidGuestAccessTokenhelper. The error envelope on a missing or invalid guest principal now readsNot authenticated - guest principal cannot resolve a user_id …so operators can grep for it. Behavior under a valid token is unchanged. Regression coverage:tests/integration/guest_invalid_bearer_routes.test.tsasserts401for/issues/submit,/issues/add_message,/issues/status,/subscribe,/unsubscribe,/list_subscriptions,/get_subscription_status,/events/stream, and/entities/duplicateswhen the bearer is not a valid guest token. - Codex / OpenAI function-tool compatibility for the issue MCP tools.
submit_issue,add_issue_message, andget_issue_statusno longer carry a top-levelanyOfin their JSON Schema, because OpenAI's function-tool registry rejects schemas with a top-level combinator. Server-side enforcement is unchanged:submit_issuestill returns400 ERR_REPORTER_ENVIRONMENT_REQUIREDwhen neitherreporter_git_shanorreporter_app_versionis supplied (declared indetails.acceptable_field_groups), andadd_issue_message/get_issue_statusstill requireentity_idorissue_number. Tool descriptions indocs/developer/mcp/tool_descriptions.yamlnow describe the constraints in prose so MCP clients see the same contract without the schema combinator. - Operator hardening knobs are now documented in the security tree.
SECURITY.mdanddocs/security/threat_model.mdadd theOperator hardening knobs (v0.12+)section:NEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN(default30/min, key precedence AAuth thumbprint > hashed guest token > IP),NEOTOMA_GUEST_TOKEN_TTL_SECONDS(default2592000, withrevoked_at-aware revocation),NEOTOMA_HOSTED_MODE=1(rejects private/loopback/link-localsender_peer_urlon inbound peer-sync), andMCP_PROXY_FAIL_CLOSED=1(refuses unsigned downstream requests on AAuth proxies). All four were already shipping behaviors in v0.12.0; this release is what makes them findable from the security landing page. neotoma doctor --jsonis now spec-documented.docs/developer/cli_reference.mdadds a Doctor section that describes the--jsonshape, everydata.risks[].code(icloud_drive,macos_synced_desktop_or_documents,prior_sqlite_repair_artifacts),suggested_safe_data_dir, the migration command (neotoma storage set-data-dir <path> --move-db-files), and the--tooloverride consumed byneotoma setup --output json.reload_neotoma_launchagents.sh --kill-zombiesis documented end to end.docs/developer/launchd_dev_servers.mdanddocs/developer/scripts_reference.mddescribe the four orphan patterns the flag SIGTERMs (legacynode dist/index.jsadopted by launchd,with_branch_ports.js → tsx → src/actions.tschains,tsx watch … src/actions.tswatchers from integration tests, andnpm exec tsx … src/actions.tsdebug runs) and call out that the steady-state orphan rate after the v0.12.0 process-group fix is near zero —--kill-zombiesis the recovery path for pre-v0.12.0 leftovers and force-killed test parents.bulk_close_issues/bulk_remove_issuesare now declared in the spec table.docs/specs/MCP_SPEC.mdadds rows for both tools with their HTTP twins (POST /issues/bulk_close,POST /issues/bulk_remove);docs/subsystems/issues.mddocuments their MCP signatures and notes thatbulk_remove_issuesis a soft delete viadeleteEntityobservations and restoration goes throughrestore_entity. The tools shipped in v0.12.0; the spec table omitted them.storewrite-classification, peer attribution, and external-actor fields are spelled out in the spec.docs/specs/MCP_SPEC.mddocuments the v0.12+observation_source(sensor/workflow_state/llm_summary/human/import/sync),source_peer_id, andexternal_actorfields on thestorerequest, including the reducer tie-break behavior (source_priorityfirst, thenobservation_source) and the AAuth-vs-external_actordistinction (signing agent vs the human/account on whose behalf the agent wrote).- Inspector packaging fails closed.
scripts/build_inspector.jsnow exits non-zero when theinspector/submodule is missing duringprepublishOnly/pack:local, instead of silently skipping. This prevents shipping an npm tarball without the bundled Inspector.tests/contract/package_scripts.test.tspins the Inspector Vite entrypoints (dev:vite,build:vite,build:watch,preview) to--config vite.config.tsso the build cannot regress to a stalevite.config.js. - Four new operator-facing site pages cover the v0.12 subsystems.
/peer-sync,/subscriptions,/issue-reporting, and/security-hardeningare wired into the docs nav, the SEO metadata, the route table, and the doc manifest. Each page links back to its repo source of truth (docs/subsystems/peer_sync.md,docs/subsystems/subscriptions.md,docs/subsystems/issues.md,SECURITY.md+docs/security/threat_model.md). The changelog page surfaces a v0.12.0 highlight banner pointing at these pages and the breakingsubmit_issuereporter-provenance contract. - Release skill now hard-gates security review.
.cursor/skills/release/SKILL.mdand.claude/skills/release/SKILL.mdadd a hard gate before Step 4 that requires explicit G1 / G2 / G3 / G4 evidence and a populatedsecurity_review.mdwith the supplement linked under aSecurity hardeningsection. The skill also requires re-running Step 3.5 when any commit is added after the security review ran. This is the workflow change that produced this v0.12.1 release plan.
What changed for npm package users
MCP tools
submit_issue,add_issue_message,get_issue_statusJSON Schemas no longer carry a top-levelanyOf. The server still returns400 ERR_REPORTER_ENVIRONMENT_REQUIREDonsubmit_issuewhen neitherreporter_git_shanorreporter_app_versionis supplied, and still requiresentity_idorissue_numberon the other two. Codex and other strict OpenAI function-tool consumers can now register the schemas without rejection. Existing MCP clients that already pass a valid payload see no behavior change.- Updated tool descriptions surface the reporter-environment requirement and the
entity_id-or-issue_numberrequirement in prose.
HTTP API
- No new operations. No
openapi:bc-diffbreaking changes vsv0.12.0. tests/integration/guest_invalid_bearer_routes.test.tscodifies that the following routes return401(not anonymous downgrade) when called withAuthorization: Bearer <invalid-guest-token>:GET /entities/duplicates,GET /events/stream,POST /get_subscription_status,POST /issues/add_message,POST /issues/status,POST /issues/submit,POST /list_subscriptions,POST /subscribe,POST /unsubscribe.
CLI
neotoma api start --helpnow surfaces the--env dev/--env prodrequirement explicitly.tests/cli/cli_infra_commands.test.tspins the help output to mention--env dev or --env prodand theneotoma api start --env prodinvocation.
API surface & contracts
- OpenAPI: unchanged vs
v0.12.0.npm run openapi:bc-diffreports no breaking changes. - MCP tool schemas:
submit_issue,add_issue_message,get_issue_statusdrop the top-levelanyOffor OpenAI / Codex compatibility (server-side enforcement preserved).tests/contract/openclaw_plugin.test.tscodifies the absence of top-levelanyOfand the presence ofproperties.reporter_git_sha/properties.reporter_app_versiononsubmit_issue. - Schema seeding: unchanged.
storerequest schema documentation: the optional v0.12+ fieldsobservation_source,source_peer_id, andexternal_actorare now described indocs/specs/MCP_SPEC.mdtogether with their reducer semantics.
Behavior changes
- Guest auth path treats invalid bearer tokens as
401, not as anonymous downgrade. Routes that accept guests now require the guest principal to validate against the persisted token grant before being stamped on the request. This closes a gap where a syntactically valid but unrecognized bearer could bypass the validation step on guest-capable surfaces. prepublishOnly/pack:localfail closed when the Inspector submodule is missing. Operators who package or publish must rungit submodule update --init inspectorfirst; the previous "skip and continue" behavior is gone.
Agent-facing instruction changes
.cursor/skills/release/SKILL.mdand.claude/skills/release/SKILL.mdadd the Hard gate before Step 4 with the G1–G5 evidence checklist and the explicit "rerun Step 3.5 if any commit is added after the security review" rule.docs/specs/MCP_SPEC.mddocuments thebulk_close_issues/bulk_remove_issuesMCP tools (and their HTTP twins) and theobservation_source/source_peer_id/external_actorfields onstore.docs/subsystems/issues.md,peer_sync.md, andsubscriptions.mdalign with the spec table additions and document the canonicalGET /events/stream?subscription_id=<id>SSE path (the legacy/subscriptions/sseshorthand was removed before v0.12.0; v0.12.1 removes the last reference).
Tests and validation
npx tsc --noEmitnpx vitest run tests/integration/guest_invalid_bearer_routes.test.ts --reporter=verbosenpx vitest run tests/contract/openclaw_plugin.test.ts --reporter=verbosenpx vitest run tests/contract/package_scripts.test.ts --reporter=verbosenpx vitest run tests/cli/cli_infra_commands.test.ts --reporter=verbosenpm run openapi:bc-diff(no breaking changes vsv0.12.0)npm run security:classify-diffnpm run security:lintnpm run security:manifest:checknpm run test:security:auth-matrix
Breaking changes
- None at the HTTP layer. None at the schema layer.
- The MCP schema change is non-breaking for compliant clients (the
anyOfwas a JSON Schema combinator MCP clients did not rely on for behavior; server-side enforcement still rejects payloads that omit the required fields). It fixes behavior for Codex / OpenAI function-tool consumers that previously could not register the schemas at all. - The Inspector packaging fail-closed (
scripts/build_inspector.jsexits non-zero when the submodule is missing) is breaking only for ad-hocnpm packruns that were intentionally relying on the prior skip; the supported flow is to initialize the submodule before packaging.
Migration guide
- MCP clients on Codex / OpenAI: no action; the JSON Schema simplification removes the previous registration error. If you implemented a workaround that synthesizes the
anyOfclient-side, you can drop it. - Operators packaging Neotoma locally: run
git submodule update --init inspectorbeforenpm run pack:localornpm publish. The build will now exit1instead of producing a tarball without the bundled Inspector. - Operators on hosted / multi-tenant deployments: if you have not already, set
NEOTOMA_HOSTED_MODE=1,MCP_PROXY_FAIL_CLOSED=1, and reviewNEOTOMA_GUEST_WRITE_RATE_LIMIT_PER_MIN/NEOTOMA_GUEST_TOKEN_TTL_SECONDS. The newOperator hardening knobs (v0.12+)section inSECURITY.mdanddocs/security/threat_model.mdis the canonical reference; nothing about the runtime defaults changed in this release.
Security hardening
This release ran the v0.12 G1–G4 security gate on the v0.12.1 diff. Findings, suggested negative tests, residual risks, and the sign-off verdict live at docs/releases/in_progress/v0.12.1/security_review.md.
Headline:
- The guest-token validation tightening in
src/actions.tsis the security-relevant code change. Regression coverage lives intests/integration/guest_invalid_bearer_routes.test.tsand the existingtest:security:auth-matrixlane. - The MCP schema simplification (
src/tool_definitions.ts) is not a security-relevant change — server-side enforcement ofreporter_git_sha-or-reporter_app_versiononsubmit_issueandentity_id-or-issue_numberonadd_issue_message/get_issue_statusis unchanged. - Operator-facing hardening knob documentation does not change runtime behavior; it makes already-shipped knobs findable from the security landing page so hosted-mode operators are less likely to leave them at single-tenant defaults.
- No new advisory under
docs/security/advisories/. No CVE.
Deferred follow-up
- Inspector UI for plans on issues (carried from v0.12.0): the
Planstab onIssueDetailPage, per-message plan chips, and the related contract test remain deferred. The v0.12.0 supplement (now archived underdocs/releases/completed/v0.12.0/) describes the scope.
Commits (v0.12.0 → v0.12.1)
3860745Merge test/current-branch-build for v0.12.16490110Update v0.12.1 security review evidence23be0bfBump version to v0.12.17009ee7Pre-release: include pending changes for v0.12.1
Full compare: v0.12.0...v0.12.1
Security Fixes
- Guest auth path now returns 401 for invalid bearer tokens instead of downgrading to anonymous access – closes a validation gap that could bypass authentication checks.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About markmhendrickson/neotoma
Deterministic state layer for AI agents. Stores versioned entities (contacts, tasks, transactions, decisions) with immutable observations, full provenance, and schema-first extraction. Local-first SQLite, cross-client memory across Claude, Cursor, ChatGPT, and OpenClaw. Website
Related context
Related tools
Beta — feedback welcome: [email protected]