Skip to content

Release 0.11.0: security hardening + 10-issue improvement program#35

Merged
blackaxgit merged 38 commits into
mainfrom
1.11.0
Jun 7, 2026
Merged

Release 0.11.0: security hardening + 10-issue improvement program#35
blackaxgit merged 38 commits into
mainfrom
1.11.0

Conversation

@blackaxgit

Copy link
Copy Markdown
Owner

Summary

Releases v0.11.0 (bumped from 0.10.1). 38 commits: a security fix campaign followed by the 10-issue source-improvement program from docs/CLX_SOURCE_IMPROVEMENT_PLAN.md. Merging this PR triggers release-plz → tag v0.11.0release.yml (arm64 macOS build + GitHub Release + Homebrew).

⚠️ Schema migration v8 → v9 (one-time purge of secret/malformed learned rules). Older binaries will refuse a v9 database — this is expected and guarded.

Highlights

Security

  • Read-only command classifier rewritten (token-parse + default-deny); closes ~15 auto-allow bypasses (env-prefixed exec, awk system(), find/fd exec, interpreter -e/verbose, git config/branch, tar/zip, sed exec flags, arbitrary-fd redirection, metachar evasion).
  • Learned-rules DB no longer ingests secrets/malformed patterns; v9 migration purges existing offenders.
  • L0 denies redirection/tee/cp/mv/dd writes into protected config dirs.
  • No auto-blacklist from automated LLM denials; injective L1 cache key; strict rules import validation.

Added

  • Graylist (ask) policy tier + asymmetric compound-command matching.
  • clx config get/set; clx rules export/import + scope-aware reset.
  • CLAUDECODE host detection (interactive Claude Code no longer mistaken for Codex).
  • Route-derived embedding dimension + drift detection.

Fixed

  • clx health warns on unresolved routes; agent memory files writable while settings/hooks protected; MCP UTF-8-safe line reads; recall degraded signal; Azure probe timeout; cross-process fallback cooldown; transactional v1 migration.

Full details in CHANGELOG.md (0.11.0).

Verification

  • cargo test --workspace: 2141 passed / 2 failed — the 2 failures are pre-existing host-routing e2e tests (sniff_*, fail at base ce6814e), unrelated to this work.
  • cargo clippy --workspace --all-targets -- -D warnings: clean. cargo fmt --check: clean. gitleaks detect: no leaks.
  • Independent Codex review at plan and implementation stages.

Notes

  • Two documented follow-ups (non-blocking): broaden the secret-detector keyword set; a full shell redirection-target parser.
  • The 2 pre-existing sniff_* e2e failures should be triaged separately.

blackaxgit added 30 commits June 6, 2026 16:16
…-deny

- Replace allow-by-argv0-name + substring heuristics with shlex tokenization,
  quote-aware control-operator segmentation, and per-tool token deny rules;
  fail-closed on parse failure, redirection, command/process substitution.
- Closes auto-allow bypasses: env/awk(system)/sed/find-fd-exec/interpreter
  -e-or-verbose/git config-branch-tag-remote/tar/zip and shell-metachar evasion.
Distinct (cwd, command) pairs no longer collide on a shared ':' separator,
preventing reuse of a cached verdict for a different command.
A literal-colon deny/allow rule now matches a literal-colon command instead of
silently failing on the asymmetric pattern-only normalization.
Introduces config::codex_trust (ProjectTrust + read_project_trust) as the
canonical reader so clx and clx-hook can drop their duplicate copies. Preserves
global-only read, canonical-path lookup, and no repo self-declared trust.
- Convert config/trust.rs from anyhow to a typed TrustError so callers can match
  malformed / unsupported-version / IO failures.
- Remove unused Error::PolicyViolation and provider-named Error::Ollama variants.
Record/consult a file-based primary-failure marker so a recent primary outage
seen by a prior one-shot hook process short-circuits to the fallback instead of
re-hitting the dead primary every invocation.
Credential get/list now bounded-retry a present-but-empty file before erroring,
removing a spurious "corrupt" failure on the LLM-auth path; the write path keeps
its fail-closed no-overwrite guarantee.
…azard

- decay: doc now says nearest-rank (matches the code), not NIST R6.
- redaction: pass-2 iterates chars instead of byte-indexing a UTF-8 string,
  removing a latent panic/corruption hazard; ASCII output is unchanged.
RecallEngine::query returns RecallQueryResult { hits, degraded }; stage errors
set degraded instead of silently folding to empty. MCP surfaces degraded-empty
as "temporarily unavailable" and the hook never injects an outage string.
read_bounded_line accumulates bytes to the delimiter and decodes once, instead
of per-chunk lossy decoding that corrupted multibyte chars at buffer boundaries.
…_input

- Remove the unused HookDeps (built, passed as _deps, dropped while handlers
  re-loaded); handlers self-resolve config/storage. This also stops the prior
  fail-open early-return when startup storage-open failed: command validation
  now always runs (only audit/cache writes degrade) when the DB is unavailable.
- Move the production-dead parse_input wrapper under #[cfg(test)].
…function

- Use clx_core::config::codex_trust instead of the local duplicate reader.
- Remove the unreachable legacy trust-token allow block.
- Extract handle_pre_tool_use into phase helpers (fileedit guard, L0, L1
  escalation, audits); behavior and fail-closed arm ordering preserved.
…asses

Codex verification round: is_redirection_token now catches N-prefixed and &>
redirection forms, and the sed flag heuristic flags e/w inside combined flag
runs such as s///ep.
Second Codex verification round: sed danger detection now parses each
substitution to its real flag region (any flag order, any delimiter), closing
s///pe and s#...#e; redirection detection also strips a Bash named-fd prefix
so {fd}>file is rejected.
…ction guard

- Add hidden builtin PolicyRuleType::Graylist; evaluate denies per-segment (any),
  allows only when every non-cd segment is whitelisted (no any-segment bypass).
- Reclassify over-broad builtins (backtick, process-subst, default-expansion,
  source/eval/exec) to ask; narrow python -c to destructive calls.
- Add L0 deny rules for redirection/tee/cp/mv/dd into protected config dirs and
  narrow the agent-config FileEdit rule to settings/hooks.
- Extend is_read_only_command with cd/sort/uniq/cut/column (guarded).
Row-scan deletes learned_rules entries that trip the shared secret or
well-formed detectors (logged redacted); idempotent; SCHEMA_VERSION 8->9.
…decision docs

- CapabilityRoute.dimension + effective-dimension resolver (route > registry >
  legacy); Azure backend sends the configured dimension instead of a literal.
- Doc-only: default_decision applies to L1 runtime failures; disabling L1 forces ask.
…ed denials

- Strip leading env-assignments; reject raw secret/compound commands and
  malformed patterns before writing a learned rule (reuses clx-core detectors).
- DecisionSource::Automated denials never learn; user rejections still do.
…ooks

Narrow the canonical FileEdit protected-dir guard so non-sensitive agent-config
paths (memory files) are allowed; settings.json/settings.local.json/hooks and
the other config dirs stay denied. Pass automated source on the L1-deny path.
…en for Codex

Truthy CLAUDECODE takes precedence over the turn_id envelope sniff (after the
explicit CLX_HOOK_HOST override), so 'ask' no longer hard-blocks under Claude Code.
…e reset

Export/import a versioned JSON envelope (import re-validates via the shared
secret/well-formed gates, accepting wildcards); reset --learned-only is the
default and preserves explicit global allows, --all drops everything.
… allow

Codex verification round: strictly parse the imported rule_type so a "graylist"
or bogus value is rejected, never coerced into an allow rule (fail-open).
…get writes

Codex verification round: narrow the dot-claude Bash-redirection deny rules to
settings.json/settings.local.json/hooks (mirroring the FileEdit guard) so
redirecting into agent memory files is no longer blocked.
Bump workspace version 0.10.1 -> 0.11.0 and add the 0.11.0 changelog entry
(security fix campaign + 10-issue improvement program; schema v8->v9).
@blackaxgit blackaxgit merged commit df6515b into main Jun 7, 2026
4 of 8 checks passed
@blackaxgit blackaxgit deleted the 1.11.0 branch June 7, 2026 22:13
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