This release fixes issues for SREs watching stability and regressions.
✓ No known CVEs patched in this version
Topics
+12 more
Affected surfaces
ReleasePort's take
Moderate signalVersion v3.0.2 of Chameleon introduces critical security hardening and several bug fixes across its codebase.
Why it matters: Security facts with severity ≥85 (ids 61708, 61709, 61715) block bypasses and terminal‑escape injection; operators should upgrade immediately to mitigate high‑severity risks.
Summary
AI summaryUpdates P1, Known remaining, and secret across a mixed release.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Critical |
Adds decoding of hex/unicode-escaped secrets to prevent bypass of deny list. Adds decoding of hex/unicode-escaped secrets to prevent bypass of deny list. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Security | High |
Arms rsync, scp, dd, and interpreter one-liners to block secret laundering past Stop backstop. Arms rsync, scp, dd, and interpreter one-liners to block secret laundering past Stop backstop. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Security | High |
Prevents security‑idiom prose from silently disabling all taught idioms. Prevents security‑idiom prose from silently disabling all taught idioms. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Security | High |
Sanitizes trust field in statusline to prevent terminal escape injection. Sanitizes trust field in statusline to prevent terminal escape injection. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Fixes per-file clock jitter causing canonical-witness recency tiebreaks. Fixes per-file clock jitter causing canonical-witness recency tiebreaks. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Records Bash-written no-archetype files and Bash rm operations for cross‑file existence checks. Records Bash-written no-archetype files and Bash rm operations for cross‑file existence checks. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Ascends through React forwardRef/memo wrappers to correctly resolve component names in TS comprehension tools. Ascends through React forwardRef/memo wrappers to correctly resolve component names in TS comprehension tools. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Re‑creates idioms.md template and warns on refresh when the file is missing, avoiding permanent loss of taught idioms. Re‑creates idioms.md template and warns on refresh when the file is missing, avoiding permanent loss of taught idioms. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Reports profile corruption when core artifacts are missing or corrupt in get_status and detect_repo tools. Reports profile corruption when core artifacts are missing or corrupt in get_status and detect_repo tools. Source: llm_adapter@2026-07-13 Confidence: low |
— |
| Bugfix | Low |
Catches and repairs fix‑wave regressions such as placeholder hops in blast‑radius parity and crashes on damaged conventions.json. Catches and repairs fix‑wave regressions such as placeholder hops in blast‑radius parity and crashes on damaged conventions.json. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Low |
Surfaces parse failures for corrupt tsconfig.json and pyproject.toml instead of silent swallowing. Surfaces parse failures for corrupt tsconfig.json and pyproject.toml instead of silent swallowing. Source: granite4.1:30b@2026-07-13-audit Confidence: low |
— |
| Bugfix | Low |
Corrects no‑remote monorepo workspace repo_id, summary, and nested_profile_warnings. Corrects no‑remote monorepo workspace repo_id, summary, and nested_profile_warnings. Source: granite4.1:30b@2026-07-13-audit Confidence: low |
— |
| Bugfix | Low |
Consumes NestJS implements heritage for class contracts. Consumes NestJS implements heritage for class contracts. Source: granite4.1:30b@2026-07-13-audit Confidence: low |
— |
| Bugfix | Low |
Captures Python async/await signal handling correctly. Captures Python async/await signal handling correctly. Source: granite4.1:30b@2026-07-13-audit Confidence: low |
— |
Full changelog
Whole-plugin from-scratch real-world QA campaign: 29 parallel testers exercised
the real plugin surface (real hook binaries, in-process MCP tools, skills, and
infra) against the real profiled repos across TypeScript/Ruby/Python and every
supported framework. 54 findings were confirmed and remediated, each reproduced
before fixing and re-verified by an adversarial pass; the fix wave itself was
verified, catching and repairing 3 fix-introduced regressions. Full unit suite
green (5413 passed), ruff clean.
Fixed
- Canonical-witness recency tiebreak was defeated by per-file clock jitter
(P1).select_canonicalsforwardednow=None, so every per-file recency
weight re-evaluatedtime.time(); two files sharing a commit epoch got weights
differing by sub-millisecond jitter, and because recency sorts above typicality
that jitter picked a near-empty aggregator over the real majority implementation
as the archetype witness. The clock is snapshotted once per pass.
select_canonicalsinbootstrap/canonical.py. - A hex/unicode-escaped secret in a single literal bypassed the deny (P1).
KEY = "\x41\x4b\x49\x41..."(a fully-escaped AKIA token) never hit the
concat-fold path, so the escapes were never decoded and the raw bytes never
matched. A numeric-escape-decoded scan pass (\x/\u/\Uonly, so line
numbers stay truthful) now runs alongside the fold pass._scan_with_concat_fold
inlint_engine.py. rsync/scp/ddand interpreter one-liners laundered a blocked secret past
the Stop backstop (P1). The destination-arming token list covered only
mv/cp/ln/install; arsync a b,dd if=a of=b, orpython -c "open('x','w').write(secret)"relocated a blocked secret to an unarmed path.
The extractor now arms rsync/scp positional destinations, ddof=targets, and
the quoted write-sink path inside apython -c/node -e/ruby -eone-liner.
_extract_bash_write_targetsinhook_helper.py.- A Bash-written no-archetype file, or a Bash
rm, was invisible to the
crossfile-existence check (P1). The recorder skipped a clean no-archetype file
and never saw a freshrm, so ased/rmthat broke an importer bypassed the
turn-end deny that the Edit path enforces. Clean ts/js/rb/py Bash writes are now
recorded (parity with Edit), and a Bash-deleted ts/py module is recorded so the
Stop prune feeds it to the FP-safe deleted-module advisory.hook_helper.py. - forwardRef/memo-wrapped React components were invisible to every TS
comprehension tool (P1).const X = forwardRef((props, ref) => {})returned
null from the name resolver (the arrow's parent is the wrapper call, not the
binding), dropping the component from search/callers/dup. The resolver now
ascends throughforwardRef/memo/observer/connectwrappers to the binding
name.callableNameOfinscripts/ts_dump.mjs. get_statusanddetect_reporeported a healthy enforce panel over an
unloadable profile (P1/P2). A missing/corrupt core artifact (archetypes/
canonicals/rules), a generation mismatch, an absent profile.json beside live
artifacts, or a corrupt conventions.json makesload_profile_dirrefuse and the
hooks fail open, yet both tools renderedmode=enforce. They now report the
profile corrupt, matchingget_pattern_context._profile_unrenderable_status
anddetect_repointools.py.- Security-idiom prose silently disabled ALL taught idioms (P1). An idiom
whose rationale said "never calleval()on user input" or "avoidrm -rf"
tripped the prompt-injection scan and dropped the entire idiom block from every
context-injection path. The dangerous-code sinks (eval/exec/rm-rf/os.system) are
now flagged only in an imperative context; a negated/advisory usage passes, while
an offensivealways run eval(user)still blocks._looks_suspiciousin
tools.py. - Deleting
idioms.mdthen refreshing was a silent permanent no-op (P1).
Refresh noop'd and never recreated the template or warned, so taught idioms
vanished. Refresh now re-derives once whenidioms.mdis missing (writing a
fresh template and surfacing the "restore from git history" warning), then
self-heals._refresh_repo_lockedintools.py. - The statusline trust field bypassed the line-protocol sanitizer (P1).
$p.namewas stripped of control/bidi/ANSI chars but$p.trustwas
concatenated raw, so a crafted cache could forge entries and inject terminal
escapes. Both fields now share the sanitizer.bin/chameleon-statusline.sh. - Enforcement/quality fixes (P2/P3).
get_statusremediation text no longer
tells the user to/chameleon-refresha too-new-schema profile (refresh refuses
it); the Tier-2 witness lead honorsconfidence_band(a low-confidence AST match
no longer says "mirror closely"); the Rails inheritance rule exempts a
third-party gem base (LookbooksController < Lookbook::PreviewController); the
inline-ignore override is no longer double-counted across the Pre/PostToolUse
gates;disable_sessionrecognizes an edit-only session via its enforcement
state; the merge driver's*.chameleon-merge.tmporphans are swept; a new Flask
blueprint is no longer mislabeledutil;teach_competing_import's npm-package
warning is gated to TS/JS profiles. - Independent-file findings (P2/P3). Corrupt
tsconfig.json/pyproject.toml
parse failures are surfaced (not silently swallowed); no-remote monorepo
workspacerepo_id/summary/nested_profile_warningscorrected; NestJS
implementsheritage consumed for class contracts; Python async/await signal
captured; absolute first-party phantom-import detection added;Data.define
block-form class methods attributed correctly; root-level TS extension bucketing,
stalereverse_indexschema handling,pnpm-workspacewithoutpackages:, the
duplication body-hash, blast-radius caller-edge parity, and several doc/skill
drifts fixed.orchestrator.py,conventions.py,phantom_imports.py,
prism_dump.rb,libcst_dump.py,signatures.py,symbol_index.py,
workspace.py,function_catalog.py,blast_radius.py,enforcement_calibration.py,
tool_config.py,violation_class.py,extractors/python.py,clustering.py. - Fix-wave regressions caught by the verify pass and repaired. The
blast-radius parity fix leaked<anonymous>/<module>placeholder hops into the
correctness-judge advisory — the judge now trims them while the read tools keep
the parity. The inheritance-calibration fix crashed the read path on anull
frequency/consistency in a damagedconventions.json— coerced to fail-open. The
absolute-phantom-import fix false-flagged (and could BLOCK) a real PEP 420
namespace-package import — the full dotted path is now confirmed absent before
flagging.
Known remaining (tracked)
naming-convention-violation/inheritance-convention-violationlint messages
carry no parseable line number, so the pr-review hunk-gate mis-buckets
pre-existing drift in a changed file.posttool-verify/lint_filecost scales with LINE count, not bytes; a 100KB
many-short-line file can exceed the hook's internal timeout and drop its lint.- Partial refresh carries
function_catalog.jsonverbatim, so
get_duplication_candidatesmisses duplication introduced in that refresh until
the next full refresh.
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 Chameleon
All releases →Beta — feedback welcome: [email protected]