Skip to content

fix(security): 0.40.3 deferred hardening - out-of-process code, SSRF pinning, MCP scoping#275

Merged
gizmax merged 1 commit into
mainfrom
fix/audit-deferred-hardening
Jul 11, 2026
Merged

fix(security): 0.40.3 deferred hardening - out-of-process code, SSRF pinning, MCP scoping#275
gizmax merged 1 commit into
mainfrom
fix/audit-deferred-hardening

Conversation

@gizmax

@gizmax gizmax commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Follow-up to #273 (0.40.2, merged). Finishes the three harder deferred audit items. Rebased onto main after #273 merged (supersedes the auto-closed #274).

What's in this PR

  • Code steps run out-of-process by default (CODE_STEPS_OUT_OF_PROCESS, default true): a separate Python subprocess with a secret-free env and POSIX CPU/address-space limits, really killed on timeout. Same AST validator, blocklist, and secret-free helpers re-run in the child. Parent validates before spawning; infra failures fall back to in-process.
  • HTTP-step SSRF IP-pinning: custom httpx.AsyncHTTPTransport dials the pre-validated IP while preserving Host + TLS SNI, closing the DNS-rebind TOCTOU. Mocked/non-resolvable hosts unaffected.
  • Memory MCP per-tenant scope: MEMORY_MCP_SCOPE_PREFIX enforced on add/search/list_memories/forget; forget requires + validates the owning user_id.

CI / testing

  • Tests run in-process in the suite via conftest (env + fixture) so the ~17k-test suite stays fast; the out-of-process path is covered by test_code_subprocess_runner.py.
  • pr-tests.yml Python job timeout-minutes 15 -> 20 (the suite legitimately runs ~13.5 min plus setup; the old gate cancelled a passing run at the 15 min mark).
  • Reviewed line-by-line by the lead + independently re-run: deferred modules 325 passed, code-step regression 456 passed, full CI green (17003 passed).

Residual notes (reviewed, acceptable)

  • Out-of-process adds ~170ms per code step; toggle CODE_STEPS_OUT_OF_PROCESS=false for loop-heavy workloads.
  • Memory forget validates the supplied user_id is in-prefix but cannot cross-check the memory_id owner (mem0 has no owner-by-id lookup); safe for per-tenant deployments.

…pinning, MCP scoping

Finishes the three deferred items from the 0.40.2 audit sweep.

- Code steps run out-of-process by default (CODE_STEPS_OUT_OF_PROCESS): a
  separate Python subprocess with a secret-free env and POSIX CPU/AS limits,
  really killed on timeout. Same AST/blocklist/helpers reused in the child.
  Infra failures fall back to the in-process path.
- HTTP steps pin the validated IP at connect time via a custom httpx transport
  that preserves Host + TLS SNI, closing the DNS-rebind TOCTOU. Mocked and
  non-resolvable hosts unaffected.
- Memory MCP enforces MEMORY_MCP_SCOPE_PREFIX on every tool call; forget
  requires and validates the owning user_id against the prefix.
@gizmax
gizmax merged commit 229dcba into main Jul 11, 2026
2 checks passed
@gizmax
gizmax deleted the fix/audit-deferred-hardening branch July 11, 2026 23:43
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