Ae1
- Category
- analysis-evasion
- Confidence
- 100% confidence
- Finding
Referenced artifact was not completely inspected
- Content
md arsing, iteration, or subprocess status handling: [input-and-process-safety.md](./references/input-and-process-safety.md).
Security audit
Security checks for vulnerabilities and agentic risk
This is a defensive Bash scripting guidance skill; the flagged risky commands are examples and warnings, not hidden execution behavior.
Install only if you want Bash-specific coding guidance. Review generated scripts before running them, especially any script that deletes files, uses sudo, talks to production systems, or handles secrets; the skill itself does not execute those actions.
Referenced artifact was not completely inspected
arsing, iteration, or subprocess status handling: [input-and-process-safety.md](./references/input-and-process-safety.md).
Referenced artifact was not completely inspected
anup, permissions, logging, or restartable automation: [production-patterns.md](./references/production-patterns.md).
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.
Out of scope:
- Acting as the runtime instructions themselves (those live in `SKILL.md`).
- Trigger phrasings already covered by adjacent `ia-*` skills (`validate-plugin` flags >70% description overlap as DUPLICATE_TRIGGER).
- <!-- to fill in: domain-specific exclusions when the skill drifts -->
## Trigger Context
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).
- Require env vars: `: "${VAR:?must be set}"`
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
- Separate `local` from assignment to preserve exit codes: `local val; val=$(cmd)`
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).
- Require env vars: `: "${VAR:?must be set}"`
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
- Separate `local` from assignment to preserve exit codes: `local val; val=$(cmd)`
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).
- Require env vars: `: "${VAR:?must be set}"`
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
- Separate `local` from assignment to preserve exit codes: `local val; val=$(cmd)`
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
- Require env vars: `: "${VAR:?must be set}"`
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
- Separate `local` from assignment to preserve exit codes: `local val; val=$(cmd)`
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).
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
- Separate `local` from assignment to preserve exit codes: `local val; val=$(cmd)`
- Debug tracing: `PS4='+${BASH_SOURCE[0]}:${LINENO}: '` with `bash -x` shows file:line per command
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
- End options with `--`: `rm -rf -- "$path"`, `grep -- "$pattern" "$file"`
- Require env vars: `: "${VAR:?must be set}"`
- Never `eval` user input; build commands as arrays: `cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"`
- Keep untrusted/derived bytes off the command line: never build a heredoc body or an `sh -c` string from external data. An unquoted `<<EOF` command-substitutes `$(...)`/backticks in the content, and even a quoted `<<'EOF'` breaks if a content line equals the delimiter (the heredoc ends early and the rest runs as shell). Write the data to a file with a non-shell writer and have the consumer read the file
- Allowlisting a command? Match the whole command against an anchored pattern (`^…$`), never inspect individual arguments; shell operators (`;`, `&&`, `|`, `#`, newline) smuggle a second command past a per-argument check (`rm -rf node_modules; rm -rf /`). Unrecognized syntax must fail closed to deny/ask
- Validating a path component before it reaches a destructive command? Anchor it against an allowlist (`[[ "$name" =~ ^[a-z0-9][a-z0-9._-]*$ ]]`) before `rm -rf -- "$base/$name"`. A prefix/`startswith` check on the joined path is defeated by `../` (`$base/../x` still starts with `$base`) and by a sibling directory sharing the prefix (`/srv/app` matches `/srv/app2`). When a full path must be accepted, `realpath -e` it and compare against the resolved base plus a trailing slash
- Validate external numeric text before arithmetic: array subscripts can execute commands, and leading zeros select octal. Require `[[ "$v" =~ ^-?[0-9]+$ ]]`, separate an optional minus from the digits, reject magnitudes outside the application's range before arithmetic conversion, convert the unsigned digits with `10#`, then apply the sign. `10#-08` is invalid. See Bounded signed decimal conversion below.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
umask 077 for scripts creating sensitive filesmkdir(2) mode, but GNU mkdir -m 755 explicitly sets the resulting directory to 0755 even under umask 077. For a mode-preservation test, set the fixture's mode explicitly and assert the observed result; do not loosen the service's umask./tmp's sticky bit lets only the file's owner rename or unlink it, so a second user's mv /tmp/f "$dest" fails with Operation not permitted while cp succeeds. Copy as the destination user (sudo -u <dest> cp -- /tmp/f "$target"), then remove the staging copy as its creatorps / /proc/<pid>/cmdline exposure and nothing else. Bash stores a multi-line command as one history entry, heredoc body included, and the single-line form printf %s '<value>' >"$tmp" puts the value on the command line too. Take it from stdin and let a JSON-aware writer escape it:
umask 077; tmp=$(mktemp); trap 'rm -f -- "$tmp"' EXIT
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
umask 077 for scripts creating sensitive filesmkdir(2) mode, but GNU mkdir -m 755 explicitly sets the resulting directory to 0755 even under umask 077. For a mode-preservation test, set the fixture's mode explicitly and assert the observed result; do not loosen the service's umask./tmp's sticky bit lets only the file's owner rename or unlink it, so a second user's mv /tmp/f "$dest" fails with Operation not permitted while cp succeeds. Copy as the destination user (sudo -u <dest> cp -- /tmp/f "$target"), then remove the staging copy as its creatorps / /proc/<pid>/cmdline exposure and nothing else. Bash stores a multi-line command as one history entry, heredoc body included, and the single-line form printf %s '<value>' >"$tmp" puts the value on the command line too. Take it from stdin and let a JSON-aware writer escape it:
umask 077; tmp=$(mktemp); trap 'rm -f -- "$tmp"' EXIT
No suspicious patterns detected.