container-iac-security
Skill2 starsChanged 49 days agoMITView on GitHub
Audits container and infrastructure-as-code security — Dockerfiles, docker-compose, Kubernetes manifests/helm charts, Terraform, CloudFormation, Pulumi. Finds root containers, untagged images, secrets baked into layers, privileged containers, host mounts, overly open security groups, unencrypted storage, and IAM over-privilege. Use when auditing Docker, Kubernetes, Terraform, or cloud infrastructure definitions.
- Pipes a download into a shell
- Reads credentials
In this repository23 other files it gives its agents.
- android-code-securitySkill
- auth-reviewSkill
- config-hardeningSkill
- course-platform-securitySkill
- crypto-reviewSkill
- cve-researchSkill
- data-exposureSkill
- dependency-vulnsSkill
- design-threat-reviewSkill
- django-securitySkill
- dotnet-securitySkill
- flow-securitySkill
- flutter-securitySkill
- graphql-securitySkill
- injection-flawsSkill
- laravel-securitySkill
- llm-securitySkill
- mobile-securitySkill
- rails-securitySkill
- secrets-detectionSkill
- security-auditSkill
- skill-forgeSkill
- spring-securitySkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 32
Default/weak service passwords (POSTGRES_PASSWORD: postgres) with published ports (ports: mapping to host) → HIGH
- Very specific: line 108
Optional bridge: if checkov/kube-linter/tfsec is installed (probe: ../security-audit/scripts/probe_tools.sh), run it and map its findings …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Container & IaC Security
Dockerfile
rg --files -g 'Dockerfile*' -g '*.dockerfile'Check each Dockerfile:
- No
USERdirective → runs as root → HIGH (addUSER app+COPY --chown) FROM ...:latestor untagged base → MEDIUM (unreproducible, silent breaking changes)- Secrets in build:
ARG/ENVwith keys,COPY .env, private keys copied in → CRITICAL (they persist in layers even if later deleted — check multi-stage usage) ADD http://...(remote fetch) instead ofCOPY→ MEDIUM;ADD url | shpatterns → HIGHcurl ... | shin RUN → HIGH- Package caches not cleaned,
apt-get upgradein build (non-deterministic) → LOW hygiene - Missing
HEALTHCHECKwhere orchestrator relies on it → LOW - sudo/setuid bits installed in image → MEDIUM
docker-compose / docker run scripts
privileged: true→ CRITICAL unless strongly justified (enumerating what it grants: all caps, host devices)volumes: /var/run/docker.sockmounted → CRITICAL (container escape = host root)network_mode: host→ HIGH (bypasses network isolation)cap_add: SYS_ADMIN|NET_ADMIN|...→ flag each with justification check- Host paths mounted writable (
/:/host) → CRITICAL - Default/weak service passwords (
POSTGRES_PASSWORD: postgres) with published ports (ports:mapping to host) → HIGH - Auth disabled by config on a service with published ports (
AUTH_ENABLED=false-style flags:OBOT_AUTH_ENABLED=false,DISABLE_AUTH,AUTH_REQUIRED=false,--no-auth) → Critical: port + flag = unauthenticated network callers hold the service's full plane — the obot Docker-quickstart pattern (CVE-2026-101065) mapped every request to a synthetic "nobody" user with Owner+Admin roles. Chain-check: with/var/run/docker.sockmounted in the same service, the now-unauthenticated MCP/agent runtime reaches host Docker → host-root takeover. Either signal alone is a near-miss (published port on an authed service is normal; auth-off on an unpublished dev service is a config smell) — the COMBINATION is the finding.
rg -n "ports:" docker-compose.y*ml compose.y*ml
rg -n -i "auth[_-]?(enabled|required)\s*[:=]\s*(false|no|off)|disable[_-]?auth|no[_-]?auth" docker-compose.y*ml compose.y*ml .envKubernetes
rg --files -g '*.yaml' -g '*.yml' | xargs grep -ln "kind: Deployment\|kind: Pod\|SecurityContext" 2>/dev/null- Missing/broken
securityContext:runAsNonRoot: true,readOnlyRootFilesystem: true, dropped capabilities (drop: ["ALL"]) → MEDIUM per gap, HIGH combined on internet-facing services privileged: truein containers → CRITICALhostPathvolumes, especially writable → HIGH/CRITICALautomountServiceAccountToken: true(default) on pods that don't talk to the K8s API → MEDIUM (default creds for lateral movement)- Wildcard RBAC (
verbs: ["*"],resources: ["*"]), cluster-admin bindings to services → HIGH. RBAC escalation verbs: any Role/ClusterRole grantingescalate(self-boost any role),bind(bind higher-priv roles to self), orimpersonate(become any user/SA) → Critical even scoped;verbs: ["get","list"]onsecretsat cluster scope → Critical (reads every credential)
rg -n "escalate|impersonate" -g '*.yaml' -g '*.yml' | rg "verbs|resources" # census: every verb row dispositioned
rg -n 'resources:\s*\[\s*"\*"\s*\]|apiGroups:\s*\[\s*"\*"\s*\]|verbs:\s*\[\s*"\*"\s*\]' -g '*.yaml' -g '*.yml' # census: every wildcard row dispositioned
rg -n "resources:.*secrets" -g '*.yaml' -g '*.yml' | rg -v "namespace" # census: every secret-reading role dispositionedimagePullPolicy: Alwayswith:latesttags / images from unknown registries → MEDIUM- Resource limits absent (DoS surface) → LOW
- Exposed
type: LoadBalanceron admin/debug services → HIGH - Secrets as plain
ConfigMap/env instead of Secret objects/external secrets → MEDIUM - Ingress (nginx-ingress) annotations:
rg -n "nginx\.ingress\.kubernetes\.io/(configuration-snippet|server-snippet|auth-url|rewrite-target|proxy-ssl)" -g '*.yaml' -g '*.yml'configuration-snippet/server-snippetin user-editable Ingress objects → config injection by anyone who can create Ingresses (CVE-2021-25742 family); controller must have snippets disabled → HIGH if reachablerewrite-targetwith attacker-influenced capture groups → open redirect/proxy (CVE-2021-25741 family — check controller version)auth-urlwith broad skip/bypass paths (*-snippetsoverriding auth) → HIGH- Egress: no
NetworkPolicywithEgresspolicyType for pods that fetch URLs / call external APIs → MEDIUM alone, raise the paired SSRF finding (see../injection-flaws/SKILL.md) — the fetcher can reach cloud metadata (169.254.169.254) and internal services
rg -n "policyTypes:" -g '*.yaml' -g '*.yml' # any Egress policy at all?Terraform / CloudFormation / Pulumi
rg -n -i "0\.0\.0\.0/0|::/0" -g '*.tf' -g '*.yaml' -g '*.json'
rg -n -i "ingress|cidr_blocks|security_group" -g '*.tf'
rg -n -i "hardcoded|access_key|secret_key|aws_secret" -g '*.tf'- Security groups / firewall rules:
0.0.0.0/0ingress on ports 22/3389/5432/6379/27017/etc. → CRITICAL/HIGH (port 80/443 on load balancers is fine — judge by port) - Databases/storage unencrypted at rest (
encrypt_at_rest,storage_encryptedfalse/omitted) → HIGH - Public S3/GCS buckets (
public_access_blockabsent,acl: public-read) → HIGH if data is non-static - IAM:
Action: "*"/resources: ["*"]policies attached to broad principals → HIGH; wildcard trust policies → CRITICAL. Full escalation-path analysis (PassRole+compute, self-modification, broken trust, ExternalId):references/aws-iam-escalation.md— load it whenever IAM policies or trust relationships exist in the repo. - Hardcoded cloud keys in state files/code → CRITICAL (also check
.tfstatecommitted to git) - Cloud: metadata with v1 tokens allowed → raises SSRF severity
rg -n -i "metadata_options|http_tokens|hop_limit|imdsv2" -g '*.tf' -g '*.yaml'http_tokens = "optional"/ IMDSv1 allowed on internet-facing workloads → HIGH (metadata credential theft pairs with any SSRF)- No
hop_limit = 1on containers/instances fetching user URLs → MEDIUM - Disabled logging (no
aws_flow_log,enable_auditvariants) → MEDIUM - Snapshot/backup configs absent → LOW
Serverless / FaaS (Lambda & friends)
rg --files -g 'serverless.yml' -g 'template.yaml' -g '*.tf' | head
rg -n -i "handler|runtime|iam|role" -g 'serverless.yml' -g 'template.yaml' | head -10- Wildcard IAM on functions (
Resource: "*"+Action: "*"/s3:/dynamodb: in the execution role) → HIGH; pair withaws-iam-escalation.mdpaths for chains - Trusted event payloads: SQS/Kinesis/SNS handlers treating message bodies as trusted (second-order pattern — producers are not trust boundaries; validate + scope per tenant) → Medium/High
- API Gateway without authorizer (or
NONE/open access on non-public routes;authorizationType: NONEon state-changing routes) → Critical - Function URLs / public invokes without auth → Critical
- Secrets in env vars of function defs (
environment:blocks in serverless.yml/template.yaml) → Critical (same rules assecrets-detection) - Layers/containers pulled from public registries unpinned → Medium
Reporting
Optional bridge: if checkov/kube-linter/tfsec is installed (probe: ../security-audit/scripts/probe_tools.sh), run it and map its findings onto the categories above — tools catch rule-library items greps miss (e.g. new CIS checks); you add the context triage they can't.
Group by layer (image → runtime → cluster → cloud). For each finding: the exact resource + file:line, blast radius sentence, and the hardened config snippet (e.g. the corrected securityContext block). Cross-reference CRITICAL secrets findings with ../secrets-detection/SKILL.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

