T09 · Insecure Skill Coding Practices
- Location
src/chronicle/cli.py:233- Finding
Secret validation bypass through unfiltered standard input
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
Chronicle is a coherent work-history tool, but it persistently captures broad private agent, file, prompt, command, and transcript data with several under-scoped exposure paths users should review carefully.
Install only if you are comfortable with a durable private work ledger. Review a dry run before enabling hooks, keep the ledger/CAS/spine private, avoid shell and remote hooks unless you explicitly need them, keep the canvas on loopback, inspect narration prompts before sending them to a model provider, and prefer pinning the Git install to a reviewed commit.
src/chronicle/cli.py:233Secret validation bypass through unfiltered standard input
src/chronicle/narrate.py:182Broad transcript collection can transmit sensitive session data to an external model provider
src/chronicle/canvas/server.py:155Unauthenticated canvas can expose captured history when bound to a network interface
SKILL.md:19Installation instructions use an unpinned mutable Git repository
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
The findings indicate installation and merging of hook commands into Claude/Codex configuration and behavior around git/zsh hooks, while the public description emphasizes history preservation rather than persistent agent/platform reconfiguration. Persistent config changes are risky because they can outlive the current task, affect future sessions silently, and are difficult for users to attribute or fully remove.
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Paths whose CONTENT must never enter the store. The event is still recorded — knowing
# a secret file was touched is operational state — but with content omitted.
DENY_GLOBS = [
"*.env", ".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx", "*.keystore",
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Paths whose CONTENT must never enter the store. The event is still recorded — knowing
# a secret file was touched is operational state — but with content omitted.
DENY_GLOBS = [
"*.env", ".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx", "*.keystore",
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Paths whose CONTENT must never enter the store. The event is still recorded — knowing
# a secret file was touched is operational state — but with content omitted.
DENY_GLOBS = [
"*.env", ".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx", "*.keystore",
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Paths whose CONTENT must never enter the store. The event is still recorded — knowing
# a secret file was touched is operational state — but with content omitted.
DENY_GLOBS = [
"*.env", ".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx", "*.keystore",
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"*.env", ".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx", "*.keystore",
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
"*/Keychains/*", "*.keychain*", "*/.docker/config.json",
"*.kdbx", "*.jks", "*/service-account*.json", "*/.npmrc", "*/.pypirc",
]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
"*/Keychains/*", "*.keychain*", "*/.docker/config.json",
"*.kdbx", "*.jks", "*/service-account*.json", "*/.npmrc", "*/.pypirc",
]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
"*/Keychains/*", "*.keychain*", "*/.docker/config.json",
"*.kdbx", "*.jks", "*/service-account*.json", "*/.npmrc", "*/.pypirc",
]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"id_rsa*", "id_dsa*", "id_ecdsa*", "id_ed25519*", "*.ppk",
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
"*/Keychains/*", "*.keychain*", "*/.docker/config.json",
"*.kdbx", "*.jks", "*/service-account*.json", "*/.npmrc", "*/.pypirc",
]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"*credential*", "*secret*", "*.secrets", "*token*", "*password*",
"*/.ssh/*", "*/.aws/*", "*/.gnupg/*", "*/.config/gh/*", "*/.netrc", "*netrc",
"*/Keychains/*", "*.keychain*", "*/.docker/config.json",
"*.kdbx", "*.jks", "*/service-account*.json", "*/.npmrc", "*/.pypirc",
]
# Content that looks like a live credential is masked in-place rather than dropping the
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
r"\.pyc\b", r"\btarget/debug\b", r"\.DS_Store\b", r"\bcoverage\b", r"\.tox\b",
r"\bvenv\b", r"\.venv\b", r"chron-selftest", r"pytest-of-",
# Build output directories, matched as a PATH SEGMENT. An earlier version required a
# trailing slash (`\bbuild\b/`), so `rm -rf ./build` — the single most common safe
# destructive command there is — was denied. False positives are how a gate gets
# switched off, so this pattern is deliberately generous about separators.
r"(^|[\s/])\.?/?(build|dist|out|_build)/?(\s|$)",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
check("cas verify", cas_verify(d1))
check("deny .env", path_denied("/a/b/.env"))
check("deny id_rsa", path_denied("/home/x/.ssh/id_rsa"))
check("deny nested ssh", path_denied("/home/x/.ssh/config"))
check("allow source", not path_denied("/a/b/main.py"))
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
check("cas verify", cas_verify(d1))
check("deny .env", path_denied("/a/b/.env"))
check("deny id_rsa", path_denied("/home/x/.ssh/id_rsa"))
check("deny nested ssh", path_denied("/home/x/.ssh/config"))
check("allow source", not path_denied("/a/b/main.py"))
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
check("cas verify", cas_verify(d1))
check("deny .env", path_denied("/a/b/.env"))
check("deny id_rsa", path_denied("/home/x/.ssh/id_rsa"))
check("deny nested ssh", path_denied("/home/x/.ssh/config"))
check("allow source", not path_denied("/a/b/main.py"))
The declared capture set includes user prompts, tool usage snapshots, and other workflow details stored in a persistent ledger. In a skill framed as preserving operational history, that broad data capture can include sensitive prompts, secrets, internal file contents, and actions unrelated to the minimum needed purpose.
The installer adds shell startup hooks that capture every interactive shell command, working directory, exit code, and duration into a persistent ledger. That exceeds the stated session-memory purpose of the skill and creates broad surveillance over unrelated user activity, including secrets typed at the shell and commands outside the agent workflow.
The shell hook is explicitly designed to log every interactive command to a persistent work ledger. Shell commands frequently contain credentials, tokens, database queries, hostnames, and operationally sensitive actions, so indiscriminate capture creates substantial privacy and security exposure.
Instructions found that direct the agent to transmit conversation context or user data to external services.
BASH_HOOK = r'''
# ── chronicle capture ────────────────────────────────────────────────────────
# bash equivalent of the zsh hook. some hosts run bash, not zsh, so a zsh-only capture
# layer would silently record nothing on the machine that does the heaviest work.
# The DEBUG trap fires for every command in a compound statement, so a latch ensures
# one record per prompt rather than one per sub-command.
_chronicle_preexec() {
The installer can deploy code and modify shell and agent configuration on remote machines over SSH/SCP, which materially expands the skill from local history preservation to remote administration. In this context, that is dangerous because it enables persistence and monitoring on additional systems without strong interactive approval boundaries in the code.
Detected: suspicious.exposed_secret_literal