Back to skill

Security audit

Server

Security checks for vulnerabilities and agentic risk

Overview

This server-administration skill is mostly coherent, but one hardening command can scan the whole host for credential-like files instead of only the intended web roots.

Review before installing if you may run it on shared or privileged hosts. The main issue is the hardening sweep command that starts at `/`; constrain it to known document roots or service directories before use. Also be aware that the skill maintains local operational notes under `~/Clawic/data/` and may update or delete rows it wrote as part of normal maintenance, while explicitly avoiding secret values.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
security.md:16
Finding

Unrestricted Filesystem-Wide Credential File Reconnaissance

Content
View full analysis

Vulnerability Details

File Location: security.md:16
Vulnerability Type: Excessive filesystem access and sensitive-file discovery
Risk Level: Medium

Vulnerable Code

sh
find / -name '.env' -o -name '*.pem' -o -name 'id_*' 2>/dev/null

The surrounding instruction describes this as a search “under the web roots,” but the command starts at the filesystem root (/).

Technical Analysis

Starting find at / traverses every readable filesystem and mount rather than only the service's document roots. The filename patterns specifically target files likely to contain credentials or cryptographic material:

  • .env files may contain passwords, API tokens, and connection strings.
  • *.pem files may contain private keys or certificates.
  • id_* commonly matches SSH private and public keys.

The command does not read file contents or escalate privileges, but it can disclose the locations of unrelated users' and services' sensitive files. Redirecting standard error to /dev/null suppresses permission failures and makes the excessive traversal less apparent.

This exceeds the minimum access needed to determine whether secrets are exposed through a particular web root. The search should be constrained to confirmed document roots and release directories belonging to the service under review.

Attack Path

  1. A user requests a service-hardening or exposure review.
  2. The Agent follows the exposure-sweep instructions in security.md.
  3. The Agent executes the provided find / ... command with the permissions available to the current account.
  4. The command traverses all readable system locations and mounted filesystems.
  5. Paths to unrelated environment files, PEM material, and SSH-key files are returned.
  6. Those sensitive paths may enter the Agent context, terminal history, audit logs, or subsequent troubleshooting workflows.
  7. A later unsafe action or compromised workflow could use this reconnaissance to target credential material ...[truncated 819 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace / with the service's explicitly confirmed web root or document root:
sh
find /srv/api/current/public -xdev \
  \( -name '.env' -o -name '*.pem' -o -name 'id_*' \) -print
  1. If multiple web roots exist, enumerate each approved path explicitly rather than searching the entire host.

  2. Use -xdev to prevent traversal into unrelated mounted filesystems.

  3. Obtain explicit user confirmation before expanding the search beyond known service directories.

  4. Avoid searching user home directories, /etc, secret-manager mounts, backup locations, and other applications' directories unless they are specifically in scope.

  5. Treat discovered paths as sensitive operational metadata. Do not persist them in Skill memory, artifacts, reports, or shared inventory unless strictly necessary.

  6. Update the instruction text so the described scope and executed command match exactly.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (29)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · containers.md (reported line 45)May include surrounding context.

md
app:
    image: ghcr.io/acme/app@sha256:9f2c1d...   # digest, not a moving tag
    restart: unless-stopped
    env_file: .env                              # 0600, never committed
    depends_on:
      db:
        condition: service_healthy

Docker Socket Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Potential security issue detected. Manual review is recommended.

Content

Scanner excerpt · containers.md (reported line 116)May include surrounding context.

md
- **Bind mounts** for data you want to see and back up by path (media, uploads, config).
- **UID mismatch is the number one bind-mount problem**: the container writes as UID 10001, the host directory is owned by 1000, and the container gets permission denied — or worse, creates root-owned files the host user cannot delete. Set `user:` to the host owner's UID:GID, or `chown` the directory to the container's UID. Many self-hosted images accept `PUID`/`PGID` for exactly this.
- `:ro` on anything the container does not need to write, config files above all.
- **Never bind-mount the container socket** (`/var/run/docker.sock`) into a service that does not need it: access to it is root on the host. Proxies with a docker provider do need it — mount it read-only and understand that read-only does not meaningfully reduce that risk.
- A named volume is not a backup. It lives on the same disk, and `down -v` deletes it (`maintenance.md`).

## Depends On Is Not Ready

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · memory-template.md (reported line 56)May include surrounding context.

md
Nothing under `~/Clawic/data/` ever holds a secret value — not the files named here, not files you create, not text the user pastes in and asks you to keep. This matters most for the files nobody planned: a runbook carries the connection string, a "config that finally worked" carries the token, a pasted `.env` is nothing but secrets. Store the pointer in its place, in this shape: `<kind>:<locator>`.

`env:DATABASE_URL` · `file:/etc/myapp/env` · `file:~/.ssh/id_ed25519` · `keychain:deploy-key` · `1password:Infra/prod-db` · `bitwarden:servers/api-token` · `vault:secret/prod/api` · `profile:deploy`

When the user pastes something to save, replace each secret value before writing and leave the pointer visible: `DATABASE_URL=<env:DATABASE_URL>`, `ssl_certificate_key <file:/etc/letsencrypt/live/example.com/privkey.pem>;`. Say in one line that you did it.

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · memory-template.md (reported line 167)May include surrounding context.

md
Nothing under `~/Clawic/data/` ever holds a secret value — not the files named here, not files you create, not text the user pastes in and asks you to keep. This matters most for the files nobody planned: a runbook carries the connection string, a "config that finally worked" carries the token, a pasted `.env` is nothing but secrets. Store the pointer in its place, in this shape: `<kind>:<locator>`.

`env:DATABASE_URL` · `file:/etc/myapp/env` · `file:~/.ssh/id_ed25519` · `keychain:deploy-key` · `1password:Infra/prod-db` · `bitwarden:servers/api-token` · `vault:secret/prod/api` · `profile:deploy`

When the user pastes something to save, replace each secret value before writing and leave the pointer visible: `DATABASE_URL=<env:DATABASE_URL>`, `ssl_certificate_key <file:/etc/letsencrypt/live/example.com/privkey.pem>;`. Say in one line that you did it.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · security.md (reported line 16)May include surrounding context.

md
1. `ss -tlnp` — every listener. Anything on `0.0.0.0` that is not the proxy is a finding: databases, admin UIs, metrics endpoints, message brokers, the app itself.
2. `iptables -S` / `nft list ruleset` — the rules actually in force, including the ones a container runtime inserted (below). `ufw status` is a summary of one tool's intentions, not the kernel's state.
3. From another machine: a port scan of the public IP. What answers from outside is the only exposure that counts, and it regularly differs from what the firewall config implies.
4. `find / -name '.env' -o -name '*.pem' -o -name 'id_*' 2>/dev/null` under the web roots — a secret inside a served directory is a download, not a secret (`static.md`).

An app bound to `0.0.0.0:8080` behind a proxy is reachable directly on 8080: TLS bypassed, forwarded-header trust bypassed, rate limits bypassed, and auth done at the proxy bypassed entirely. Bind loopback or a Unix socket (SKILL.md Rule 7).

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · selfhosted.md (reported line 81)May include surrounding context.

md
- Self-hosted git (Forgejo, Gitea, GitLab) needs SSH as well as HTTPS: either a second host port for SSH or the proxy's stream module for TCP passthrough, and the app's advertised clone URL must match whichever you chose or every copied clone command is wrong.
- CI runners execute arbitrary code by design. Never on the same box as anything valuable, never with the container socket mounted, and with a disk they are allowed to fill.
- GitLab's resting memory footprint is in gigabytes; Forgejo and Gitea are in hundreds of megabytes. On a small box this is the entire decision.
- Registry storage grows without limit unless a retention policy exists — and it is a disk-full outage that arrives with no warning.

## Game Servers

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
60% confidence
Finding

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).

Content

Scanner excerpt · tls.md (reported line 97)May include surrounding context.

md
For service-to-service traffic on a private network, a private CA (or the platform's built-in issuer) beats public certificates: no rate limits, no public DNS requirement, and the trust store is yours. The cost is distributing the CA bundle to every client and rotating it — which is real work, so only take it on when the network is genuinely untrusted or a compliance regime requires it.

Never disable verification to make it work. `insecure_skip_verify`, `curl -k`, and `verify=False` turn TLS into obfuscation, and they are permanent: nobody comes back to remove them.

## mTLS

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · containers.md (reported line 101)May include surrounding context.

md
| `unless-stopped` | Restart always, **except** if you stopped it deliberately — the right default for services |
| `always` | Restarts even after a deliberate stop when the daemon restarts, which surprises people mid-maintenance |

`unless-stopped` only survives a reboot if the container runtime's own service is enabled at boot. On a systemd host: `systemctl is-enabled docker`. This is the container equivalent of `systemctl enable` and it is skipped just as often (`processes.md`).

## Publishing Ports Safely

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · containers.md (reported line 101)May include surrounding context.

md
| `unless-stopped` | Restart always, **except** if you stopped it deliberately — the right default for services |
| `always` | Restarts even after a deliberate stop when the daemon restarts, which surprises people mid-maintenance |

`unless-stopped` only survives a reboot if the container runtime's own service is enabled at boot. On a systemd host: `systemctl is-enabled docker`. This is the container equivalent of `systemctl enable` and it is skipped just as often (`processes.md`).

## Publishing Ports Safely

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 128)May include surrounding context.

md
| `unless-stopped` | Restart always, **except** if you stopped it deliberately — the right default for services |
| `always` | Restarts even after a deliberate stop when the daemon restarts, which surprises people mid-maintenance |

`unless-stopped` only survives a reboot if the container runtime's own service is enabled at boot. On a systemd host: `systemctl is-enabled docker`. This is the container equivalent of `systemctl enable` and it is skipped just as often (`processes.md`).

## Publishing Ports Safely

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · maintenance.md (reported line 80)May include surrounding context.

md
## Reboots

- Before: check that everything is `enabled`, not merely running (`systemctl list-unit-files --state=enabled`), that the container runtime is enabled, and that nothing critical is running from a shell (`processes.md`).
- After: verify each service in `## Services` answers, not just that the box pings. The whole point of a reboot test is to discover the service somebody started by hand in March.
- A scheduled reboot in the maintenance window is far cheaper than an unplanned one at peak. A box with an uptime of 400 days is not a boast; it is an untested boot sequence carrying an unpatched kernel.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template explicitly authorizes file writes and deletions without user permission, with only a minimal one-line announcement. In an agent setting, that weakens user control over destructive actions and can lead to unintended loss or tampering of stored operational data, especially in shared files used by multiple skills.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The split procedure directs the agent to delete sections from memory.md as part of normal maintenance, but does not require a strong warning, confirmation, or rollback mechanism. That creates a real risk of accidental data loss, corruption, or inconsistent state if the move is interrupted or performed incorrectly.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · SKILL.md (reported line 114)May include surrounding context.

WantedBy=multi-user.target

text

Apply: `systemctl daemon-reload`, then `systemctl enable --now api`. **`enable` is what makes it start at boot; `start` alone does not** — the most common way a service "randomly disappears" months later is that only `start` was ever run and the box finally rebooted. Verify with `systemctl is-enabled api`, never by assumption.

Validate before installing: `systemd-analyze verify /etc/systemd/system/api.service` catches typos in directive names that systemd otherwise ignores silently — an unknown directive is a warning in the journal, not an error, so a misspelled `Restart=on-faliure` means no restart at all and nothing tells you.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 33)May include surrounding context.

WantedBy=multi-user.target

text

Apply: `systemctl daemon-reload`, then `systemctl enable --now api`. **`enable` is what makes it start at boot; `start` alone does not** — the most common way a service "randomly disappears" months later is that only `start` was ever run and the box finally rebooted. Verify with `systemctl is-enabled api`, never by assumption.

Validate before installing: `systemd-analyze verify /etc/systemd/system/api.service` catches typos in directive names that systemd otherwise ignores silently — an unknown directive is a warning in the journal, not an error, so a misspelled `Restart=on-faliure` means no restart at all and nothing tells you.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 33)May include surrounding context.

WantedBy=multi-user.target

text

Apply: `systemctl daemon-reload`, then `systemctl enable --now api`. **`enable` is what makes it start at boot; `start` alone does not** — the most common way a service "randomly disappears" months later is that only `start` was ever run and the box finally rebooted. Verify with `systemctl is-enabled api`, never by assumption.

Validate before installing: `systemd-analyze verify /etc/systemd/system/api.service` catches typos in directive names that systemd otherwise ignores silently — an unknown directive is a warning in the journal, not an error, so a misspelled `Restart=on-faliure` means no restart at all and nothing tells you.

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · processes.md (reported line 87)May include surrounding context.

md
| `MemoryHigh=1500M` | Throttles before killing — an app that slows down is easier to diagnose than one that vanishes |
| `TasksMax=4096` | A thread or fork leak takes the whole box's PID space otherwise |
| `CPUQuota=200%` | Two cores' worth; useful to keep a batch job from starving the web path |
| `OOMPolicy=stop` | Do not restart into the same OOM loop forever |

`systemctl show api -p MemoryMax,LimitNOFILE` prints what is actually in force — read it rather than the file, because a drop-in in `/etc/systemd/system/api.service.d/` may be overriding you.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 132)May include surrounding context.

md
## User Services

`systemctl --user` units live in `~/.config/systemd/user/` and need `loginctl enable-linger <user>` to run without an active login session — otherwise they stop when the user logs out, which is the exact problem supervision was supposed to solve. Fine for a personal box; for anything shared, a system unit with a dedicated user is clearer.

## PM2

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 164)May include surrounding context.

md
| Looks supervised | Actually |
|---|---|
| `systemctl start` was run, `enable` was not | Gone after the next reboot; `is-enabled` says `disabled` |
| PM2 running, no startup unit / no `pm2 save` | Gone after the next reboot, and PM2 reports everything fine until then |
| Container running, `restart: no` (the default with `docker run`) | Gone after a daemon restart or a host reboot |
| `nohup`, `screen`, `tmux` | Gone when the session, the box, or the OOM killer decides |

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

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.

Content

Scanner excerpt · processes.md (reported line 171)May include surrounding context.

md
| Unit in `failed` after a crash loop | Down and not retrying — the start limit was hit (above) |
| Unit ordered after a network mount that arrives late | Starts, fails to find its data, and the restart limit bans it before the mount appears |

Check the whole box in one pass: `systemctl list-units --state=failed` and `systemctl list-unit-files --state=enabled` together answer "what is broken" and "what will come back".

## Write It Down

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · security.md (reported line 16)May include surrounding context.

md
1. `ss -tlnp` — every listener. Anything on `0.0.0.0` that is not the proxy is a finding: databases, admin UIs, metrics endpoints, message brokers, the app itself.
2. `iptables -S` / `nft list ruleset` — the rules actually in force, including the ones a container runtime inserted (below). `ufw status` is a summary of one tool's intentions, not the kernel's state.
3. From another machine: a port scan of the public IP. What answers from outside is the only exposure that counts, and it regularly differs from what the firewall config implies.
4. `find / -name '.env' -o -name '*.pem' -o -name 'id_*' 2>/dev/null` under the web roots — a secret inside a served directory is a download, not a secret (`static.md`).

An app bound to `0.0.0.0:8080` behind a proxy is reachable directly on 8080: TLS bypassed, forwarded-header trust bypassed, rate limits bypassed, and auth done at the proxy bypassed entirely. Bind loopback or a Unix socket (SKILL.md Rule 7).

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · processes.md (reported line 71)May include surrounding context.

md
| Method | Verdict |
|---|---|
| Environment file, mode 0640, owned `root:<service>` | The workable default |
| `Environment=` in the unit | No — unit files are world-readable and values appear in `systemctl show` |
| Secret in the repository or the image | No, ever. It is now in every layer, every clone, every backup |
| Secret in a proxy config or a compose file committed to git | Same problem, one directory over |
| systemd `LoadCredential=` | Best available on a plain box: the value is a file readable only by that unit, never in the environment |

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · security.md (reported line 58)May include surrounding context.

md
| Method | Verdict |
|---|---|
| Environment file, mode 0640, owned `root:<service>` | The workable default |
| `Environment=` in the unit | No — unit files are world-readable and values appear in `systemctl show` |
| Secret in the repository or the image | No, ever. It is now in every layer, every clone, every backup |
| Secret in a proxy config or a compose file committed to git | Same problem, one directory over |
| systemd `LoadCredential=` | Best available on a plain box: the value is a file readable only by that unit, never in the environment |

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.