Data Freshness
Staleness is one of the most exploited gaps in security — not because developers don't care, but because nothing breaks until something does. By then it's too late to call it maintenance. It's an incident.
The uncomfortable truth is that a project that was fully secured six months ago may not be secured today. Software gets old. Tokens drift. Configs that made sense for your project at v1 don't necessarily make sense at v3. Attackers keep up with this. Most developers don't — not because they're careless, but because there's no alarm that goes off when something quietly becomes a liability.
This section is that alarm. Run through it regularly and you stay ahead of it. Skip it and you find out the hard way.
What Goes Stale and Why It Matters
Dependencies. New vulnerabilities are discovered in existing packages constantly. A dependency that was clean when you installed it may have a critical CVE today. It doesn't update itself. See Dependency Security and Dependency Intelligence for the full picture — but the short version is: if you haven't audited recently, audit now.
Credentials and tokens. API keys, Personal Access Tokens, deploy keys, and service account credentials don't expire unless you make them. A token you created eighteen months ago for a one-off integration may still have full access to your repo, your registry, or your cloud environment. If the project it was created for is done, the token should be too.
GitHub Actions versions. Actions pinned to tags (@v3) can silently change under you when a maintainer updates what that tag points to. Actions pinned to SHAs stay locked — but the underlying code may still have vulnerabilities that a newer version fixes. Both need periodic review. See Advanced Security for pinning guidance.
SSH keys. Keys don't expire by default. A key you generated on an old machine, a key a former collaborator used, a key you added for a server that no longer exists — all of these may still have active access. If you can't account for a key, revoke it.
Workflow permissions. As your project grows, your GitHub Actions workflows may accumulate permissions that made sense for a feature you no longer use. Permissions that aren't actively needed are attack surface that isn't earning its keep.
Your own security posture documentation. If you have a SECURITY.md, a threat model, or a list of known risks — when did you last update it? A document that describes a project you've significantly changed is worse than no document at all. It creates false confidence.
The Freshness Check — Run This Now
These commands give you a quick snapshot of where things stand. Run them on the repo you're most worried about first.
Dependencies
=== "macOS / Linux / Kali"
# Python projects
pip list --outdated
pip-audit
# If your system uses pip3
pip3 list --outdated
pip3-audit
# Node projects
npm outdated
npm audit
=== "Windows (WSL2)"
# Run the same commands inside your WSL2 terminal
pip list --outdated
pip-audit
# If your system uses pip3
pip3 list --outdated
pip3-audit
# Node projects
npm outdated
npm audit
Credentials and Tokens
Check your active Personal Access Tokens:
GitHub → Settings → Developer settings → Personal access tokens
For each token ask: Do I know what this is for? Is it still needed? When was it last used? GitHub shows last-used dates on fine-grained PATs — use that information.
Check deploy keys:
Each repo → Settings → Deploy keys
Remove any key you can't identify or that belongs to a system no longer in use.
SSH Keys
GitHub → Settings → SSH and GPG keys
Review every key listed. If you don't recognize a key name or know which machine it belongs to, remove it. A key you can't account for is a key someone else might control.
GitHub Actions
Review your workflow files for Actions pinned to tags rather than SHAs:
grep -r "uses:" .github/workflows/ | grep -v "@[a-f0-9]\{40\}"
Anything that shows a tag (@v2, @main, @latest) rather than a 40-character SHA should be reviewed and pinned. See Advanced Security for how.
How Often — Frequency Reference
💡 These are general guidelines based on common industry practices and standards (NIST, CIS Controls, DevSecOps frameworks). They represent the minimum acceptable baseline — not the ceiling. If you ship actively, work in security, or just take this seriously, the "Paranoid & Preventative" column is where you want to be.
| What | Industry Standard | Paranoid & Preventative |
|---|---|---|
npm audit / pip-audit |
Every dependency addition; minimum weekly | Every commit, every dependency addition, every deploy |
npm outdated / pip list --outdated |
Monthly | Weekly |
| Personal Access Tokens review | Monthly | Bi-weekly; rotate every 90 days max |
| Deploy keys review | Monthly | Monthly; rotate every 60 days |
| SSH keys review | Quarterly | Monthly |
| GitHub Actions versions review | Quarterly | Monthly |
| Workflow permissions audit | Quarterly | Every time a workflow changes |
SECURITY.md and documentation review |
Every major version | Every significant change, minimum quarterly |
| Full repo security posture review | Every 6 months | Quarterly |
| Collaborator access audit | When someone leaves | Monthly — people's roles change, access should too |
| Dependabot alerts triage | Weekly | Daily |
💡 Make it a habit, not an event The developers who stay ahead of staleness aren't running massive quarterly audits — they're doing small checks consistently. Five minutes after every dependency addition. A quick token review at the start of each month. It compounds over time into a project that's genuinely hard to exploit through neglect.
Signs Something Has Gone Stale
Not everything shows up in an audit command. Watch for these behavioral signals:
- A dependency you rely on has gone quiet — no commits, no releases, no maintainer activity in over a year. Unmaintained packages don't get security patches.
- You get a Dependabot alert you've been dismissing. Every dismissed alert is a decision. Make sure it was a deliberate one.
- A collaborator left the project and you haven't audited access since.
- You added a token or key for a feature that got cut and never cleaned it up.
- Your GitHub Actions workflows haven't been touched in months but your project has changed significantly around them.
- You shipped a major version and never updated your
SECURITY.md.
Any of these is a signal to run the freshness check above before moving on to the next feature.
Freshness Checklist
□ Dependencies audited for known CVEs
□ Outdated packages identified and update plan in place
□ Personal Access Tokens reviewed — unused tokens revoked
□ Deploy keys reviewed — unrecognized keys removed
□ SSH keys reviewed — unaccountable keys removed
□ GitHub Actions pinned to SHAs, not tags
□ Workflow permissions reviewed and scoped to minimum
□ SECURITY.md and documentation current
□ Dependabot alerts reviewed — none dismissed without a reason
□ Collaborator access reflects current team
Where This Goes Next
Freshness keeps you current. But what happens when something goes wrong despite your best efforts — when you need to go back to a known good state?
→ Backup & Recovery — What a real backup strategy looks like for a GitHub-based project and how to recover from the worst.
@sudochef — Build like you're the target. Because you are.