DEV Community

Tarun Jaswani
Tarun Jaswani

Posted on

Deleting a Password From Your Code Does Not Remove It. Git Remembers Everything, and So Does Everyone Who Cloned the Repository.

Uploading image
Someone commits an API key by accident, notices within the hour, deletes it and pushes the fix. The team considers the incident closed. It is not closed. The key is still in the commit history, still in every clone, still in every fork, and still valid — because deleting a line of code and rotating a credential are completely different actions and only one of them happened.
Security Researcher • Penetration Tester
Tarun Jaswani is an independent security researcher and penetration tester with over five years in offensive security, 100+ accepted vulnerability reports, and Hall of Fame recognition from Google, Zoho, TripAdvisor and Adafruit. He writes about security for the people who have to build and defend real systems.

This is the most common serious finding I encounter, and it is almost always discovered by accident. Not through a clever technique — by reading the repository history. A cloud access key committed during initial setup two years ago and removed the following week. A database password in an old configuration file. A payment gateway secret in a test script somebody wrote once. Each was deleted promptly and none was ever rotated, which means each is still live, still in the history, and still available to anyone who has ever had access to that repository.
https://about.me/tarun_jaswani
The mental model behind the mistake is understandable. In most systems, deleting something removes it. Version control is specifically designed to do the opposite — its entire purpose is that nothing is ever lost. That property is enormously useful and it makes a committed secret permanent by default.
https://dev.to/tarun_jaswani_e9a4c1020df/secure-coding-starts-before-the-first-line-of-code-4gbl
Why Deletion Does Not Work.
• The commit that added the secret still exists in history and can be read by anyone with repository access, including read-only access.
• Every clone taken before the deletion contains it. You cannot recall those, and you usually cannot enumerate them.
• Forks are independent copies. A public repository that was forked before the fix has distributed the secret to strangers permanently.
• Continuous integration logs, build artefacts and caches may contain it independently of the repository.
• Rewriting history to purge it is possible, disruptive, and still does not invalidate copies already taken.
Which leads to the only reliable rule: once a secret has been committed, treat it as compromised. Not possibly compromised. Compromised. The question is not whether to rotate it but how quickly.
The single rule
A secret that has ever been committed is burned. Rotate it. Cleaning the history is housekeeping — useful, but it is not remediation, and doing only that leaves a live credential in circulation.
Where Secrets Actually End Up.
REPOSITORY HISTORY
The obvious one, and still the most common. Configuration committed before someone set up environment variables. A test file with real credentials because the test needed to actually work. An environment file added before the ignore rule existed — note that the ignore rule prevents future commits and does nothing about the one already in history.
CLIENT-SIDE BUNDLES
Anything shipped to a browser or a mobile app is public, regardless of how it was compiled, minified or obfuscated. A key in a frontend build is a published key. Mobile applications are worse, because developers assume compilation provides protection and application binaries are trivially extractable.
CI AND BUILD LOGS
Pipelines print things. A verbose build step echoing an environment variable, a failing test dumping its configuration, a deployment script logging its own arguments. Build logs are frequently readable by a much larger group than the repository itself, and nobody thinks of them as a data store.
THE PLACES PEOPLE PUT THINGS TEMPORARILY
Shared documents, chat messages, ticket comments, screenshots pasted into an incident channel. These have no rotation, no expiry and no access review, and they persist for years in systems with far weaker controls than the repository everyone worries about.
https://dev.to/tarun_jaswani_e9a4c1020df/lessons-every-cybersecurity-engineer-learns-from-real-world-web-applications-4pn1
What Actually Fixes This.

  1. Scan history, not just the current state. Run a secret scanner across the full commit history of every repository you own. Most teams doing this for the first time find something, and the something is usually still valid.
  2. Rotate everything you find, then clean the history. In that order. Rotation is remediation; history rewriting is tidying up afterwards.
  3. Put scanning in the pre-commit hook and the pipeline. Catching a secret before it is committed is trivially cheap. Catching it afterwards is an incident.
  4. Move to a secrets manager rather than environment files. Centralised storage with access control, audit logging and rotation support removes the class of problem rather than policing it.
  5. Prefer short-lived credentials wherever the platform supports them. A token that expires in an hour is a far smaller problem than a static key that lives for three years.
  6. Set rotation schedules and actually run them. A credential that has never been rotated has an unbounded exposure window, and you have no way to know whether it leaked years ago.
  7. Assume anything client-side is public. If a mobile app or frontend needs privileged access, the privileged call belongs on a backend you control, with the client authenticating to it. https://github.com/tarunjaswani/Vulnerabilities-notes https://github.com/tarunjaswani/CORS-Misconfiguration The Detection Question Nobody Asks. Suppose one of your keys leaked two years ago and somebody has been using it quietly since. How would you know? For most organisations the honest answer is that they would not, because credential use is rarely monitored for anomaly — only for failure. • Log credential usage with source context, so a key suddenly being used from an unfamiliar location or at an unusual hour is visible. • Alert on service credentials used outside their expected pattern. Machine credentials are highly predictable, which makes deviation unusually easy to detect. • Scope every credential to the minimum it needs. A leaked key restricted to reading one bucket is an incident; the same key with broad account access is a catastrophe. • Keep an inventory of which credentials exist, what they access, who owns them and when they were last rotated. Most organisations cannot produce this list, which is itself the finding. https://dev.to/tarun_jaswani_e9a4c1020df/why-identity-is-the-new-security-perimeter-29c6 https://github.com/tarunjaswani/awesome-cybersec A Realistic First Week.
  8. Run a history scan across your repositories today. It takes minutes and the results are usually sobering.
  9. Rotate every live credential the scan surfaces, starting with anything granting write or administrative access.
  10. Add scanning to the pipeline so the next one is caught before it lands.
  11. Write the credential inventory, even roughly. Owner, scope, last rotated.
  12. Pick the oldest never-rotated credential and rotate it. Then set a date for the next one. https://www.linkedin.com/in/tarun-jaswani-a85b55401/ https://github.com/tarunjaswani Version control is designed so that nothing is ever lost, which means a committed secret is permanent by default and deleting the line changes nothing about that. Scan the history rather than the working tree, rotate before you tidy, move credentials into a manager with rotation and audit, and keep an inventory — because the credential you cannot name is the one you will never rotate. — Tarun Jaswani https://x.com/TJaswani7857 https://dev.to/tarun_jaswani_e9a4c1020df

TAGS

Cybersecurity #AppSec #TarunJaswani #InfoSec #SecureCoding #DevSecOps #Security #Engineering #Risk #Practice

Top comments (0)