Skip to content

OpSec Mistakes Footguns

Mistakes that lead to breaches, data exposure, or compliance failures.


1. Committing secrets to git and only deleting the file

You commit an AWS access key in .env. You realize the mistake, delete the file, and commit again. The key is still in the git history. Automated scanners find it. Your AWS account is compromised within hours.

Fix: Rotate the secret immediately — assume it is compromised the moment it was pushed. Then rewrite history with git filter-repo. A delete commit does not remove anything from history.

War story: Palo Alto Networks' Unit 42 documented "EleKtra-Leak," a multi-year campaign where bots scraped AWS keys from GitHub within 5 minutes of exposure. In just over a month, researchers found 474 different crypto miners running on compromised accounts. One developer's key was used to spin up 140 EC2 instances before they noticed. Bots scan GitHub in real time — rotation must happen in minutes, not hours.


2. Using wildcard IAM permissions

You give a service account Action: * and Resource: * because scoping permissions is tedious. That service account's credentials leak (see footgun #1). The attacker now has full control of your AWS account — they can delete all S3 buckets, spin up crypto miners, and exfiltrate every database.

Fix: Follow least privilege. Scope actions to exactly what is needed. Use AWS IAM Access Analyzer to identify unused permissions. Review permissions quarterly.


3. Sharing credentials between team members

The production database password is in a shared Google Doc. Five people know it. One person leaves the company. Nobody rotates the password because "it is too much work." The ex-employee still has access.

Fix: Individual accounts with SSO for every system. Service accounts with scoped, auto-rotated credentials via a secrets manager (Vault, AWS Secrets Manager). When someone leaves, their individual access is revoked automatically.


4. Running services bound to 0.0.0.0 without auth

Redis, Elasticsearch, or MongoDB is deployed with default config, listening on all interfaces with no authentication. A port scan from the internet finds it. Your data is exfiltrated or wiped within hours.

Fix: Bind to localhost or private network interfaces. Enable authentication on every data store. Use network policies or security groups to restrict access. Regularly scan for open ports: ss -tlnp | grep 0.0.0.0.


5. No pre-commit hooks for secret detection

Developers commit secrets because there is no guardrail. You rely on code review to catch them. Code reviewers miss them because they are looking at logic, not credentials. The secret ships to the remote.

Fix: Install gitleaks or detect-secrets as a pre-commit hook. It catches secrets before they ever leave the developer's machine. Make it a mandatory part of onboarding.


6. Containers running as root

Your Dockerfile has no USER directive. Every process in the container runs as root. A container escape vulnerability gives the attacker root on the host. This is not theoretical — CVE-2019-5736 did exactly this.

Fix: Always add USER nonroot or USER 1000 in your Dockerfile. Use read-only root filesystems. Drop all capabilities. Set securityContext.runAsNonRoot: true in Kubernetes pod specs.

CVE: CVE-2019-5736 (CVSS 7.2) — a runc flaw that allowed a malicious container to overwrite the host runc binary and gain host root access. The attack required root inside the container. Running as non-root with read-only rootfs would have blocked this exploit entirely. Affected Docker < 18.09.2, containerd, CRI-O, and any runc user.


7. Ignoring patch cycles

You skip patching because it requires downtime and testing. Six months later, a critical CVE is published with a public exploit. Your system is running a version from 6 months ago. Attackers scan for it by version banner.

Fix: Establish a patching SLA: critical CVEs within 48 hours, high within 1 week. Automate security patching where possible (unattended-upgrades on Debian, automatic node upgrades in managed Kubernetes).


8. Storing secrets in environment variables visible via inspect

You pass database passwords as environment variables to Docker containers. Anyone with Docker socket access can run docker inspect and see every secret in plaintext. Container orchestration logs may also capture them.

Fix: Use a secrets manager (Vault, AWS Secrets Manager) or Kubernetes Secrets (with encryption at rest). Mount secrets as files, not environment variables. Never log environment variables.


9. No MFA on cloud provider root accounts

Your AWS root account has a strong password but no MFA. An attacker obtains the password through phishing or credential stuffing. They log in, create a new admin user, and lock you out of your own account.

Fix: Enable MFA on every cloud account, especially root/admin accounts. Use hardware security keys (YubiKey) for root accounts. Set up AWS Organizations SCPs to require MFA for sensitive operations.


10. Terraform state files with plaintext secrets

terraform.tfstate contains database passwords, API keys, and other sensitive values in plaintext. The state file is committed to git, stored on a shared drive, or left in an unencrypted S3 bucket.

Fix: Never commit terraform.tfstate to git (add to .gitignore). Use remote state with encryption (S3 + DynamoDB with server-side encryption). Enable state locking. Restrict access to the state bucket.

Gotcha: Terraform stores every resource attribute in state — including aws_db_instance passwords, tls_private_key PEM data, and aws_iam_access_key secrets. Marking a variable as sensitive in HCL only hides it from CLI output; it is still plaintext in the state file. The state file IS your secret store if you're not careful.