Why I spend so much time looking for leaks
The most valuable finding in an engagement is not always the most complicated one. Sometimes it is a file that should never have been uploaded. A .git directory, a backup archive, or a configuration file can give me more access than a carefully crafted exploit. I have learned to look for these files before I spend hours on a complex attack chain.
This post is my personal study note on hunting for sensitive information leaks. It covers version control directories, backup files, editor artifacts, configuration files, and the process I use to validate the secrets I find. The notes are practical because the goal is not to collect a long list of filenames. The goal is to find something that actually helps me move forward.
The .git directory
The most dangerous leak is an exposed .git directory. If the directory is accessible, I can download the repository history and reconstruct the source code. The source code often contains API keys, database passwords, internal URLs, and comments that explain the architecture.
The first check is simple. I request /.git/HEAD and see whether the response contains ref: refs/heads/main or a similar value. If the file is accessible, the directory is probably exposed. I also request /.git/config, which can reveal remote repository addresses and user information.
Downloading the entire repository is the next step. Tools like git-dumper walk the object database and reconstruct the working tree. The download can be large, but the result is a complete copy of the source code. I search the source for keywords like password, secret, api_key, and token.
The repository history is more valuable than the current code. Old commits often contain secrets that were removed from the current version. I check the history for deleted files and for changes that removed hardcoded credentials.
Backup files and archives
Backup files are another common leak. A developer might create a copy of the website and leave it in the web root. The backup can be a .zip, .tar.gz, .sql, .bak, or .old file. The filename is often based on the application name, the domain, or a date.
I look for backups in common locations and with common names. I also use the application's own file naming pattern to generate candidates. If the application uses a version number in its URLs, I try names like app-2024.zip, app-latest.tar.gz, and backup.sql.
A database dump is the most sensitive backup. It contains user records, hashes, sessions, and sometimes plaintext passwords. If I find a dump, I do not need to attack the database at all. I can use the credentials directly.
Editor artifacts
Editor artifacts are small files that are left behind by text editors. The most common examples are .swp, .swo, .DS_Store, and temporary files. They are easy to overlook because they are hidden and their names do not look important.
A .swp file can contain the previous version of a file that was being edited. If the file was a configuration file, the swap file may contain the secret values that were typed before they were saved. The content is not always readable, but it is worth checking.
The .DS_Store file is a macOS artifact that lists the files in the directory. If it is exposed, it can reveal the directory structure, including files that are not linked from the main page. I parse the file and use the names as candidates for further discovery.
Configuration files
Configuration files are the best source of secrets. Files like .env, config.php, settings.json, and application.properties often contain database credentials, API keys, and cloud tokens. The names are common, and the files are often placed in the web root by mistake.
The .env file is especially common in modern applications. It is used to store environment variables, including secrets. If the file is accessible, I can read the database host, the username, the password, and the API keys in one request.
Cloud credential files are another high-value target. Files such as service account JSON files or .aws/credentials grant access to cloud resources. The impact is much larger than a single database password because the credentials can be used to control the cloud account.
Documentation and logs
Documentation can leak information without containing a password. A README file might describe the architecture, the internal hostnames, and the deployment process. An internal wiki page might link to a staging environment or a database admin panel. The documentation gives me a map of the system.
Logs are another source. Debug logs can contain tokens, request bodies, and error messages. Access logs can reveal internal paths and user behavior. If a log file is exposed, I search it for sensitive values.
I also check for source maps and JavaScript bundles. Source maps are files that map the minified JavaScript back to the original source. They are often served in production by mistake. A source map can reveal the original code, including internal API calls and hardcoded values.
Validating the secrets
Finding a string that looks like a password is not the same as finding a vulnerability. I need to validate the secret before I report it. The validation must be safe and within the scope of the engagement.
The first step is to identify the service that the secret is for. A database password should be tested against the database. An API key should be tested against the API. A cloud credential should be tested with a read-only request.
I always use the least intrusive method to validate a secret. I do not want to reset a password, delete a resource, or trigger a large-scale action. A read-only request is usually enough to confirm that the secret works.
The report should not contain the secret in plaintext. I redact the value and describe where it was found and what it can access. The developer needs enough information to find the leak, but the report should not make the problem worse.
Prevention
The best prevention is to keep secrets out of source code and web-accessible directories. Secrets should be stored in a vault, a secret manager, or an environment-specific configuration that is not committed to the repository.
Secret scanning should be part of the development pipeline. A pre-commit hook, a CI check, or a repository history scan can catch a secret before it reaches production. The scan should cover not only the current code but also the commit history and the backups.
Backups should be stored outside the web root and protected with proper permissions. Logs should also be stored outside the web root and rotated regularly. The web server should not serve hidden files, backup files, or editor artifacts.
Directory listing
Directory listing is an easy way to find files that are not linked anywhere. If the web server returns a list of the files in a directory, I can see the names of backups, configuration files, and internal documents.
I check the common directories first: /backup, /uploads, /logs, /config, and /admin. The directory listing may be disabled for most paths but enabled for one specific path. I test the paths that the application uses.
The listing also reveals the file structure. The names of the files can tell me the application version, the developer names, and the internal project names. I use the names to generate new candidates for the discovery.
The listing is not a vulnerability by itself, but it is a symptom. The server should not expose the directory structure. I report the listing together with the sensitive files that it reveals.
Search engine caches
Search engines are a source of historical information. A page that was public in the past may still be cached, even after it has been removed from the application. The cache can contain login pages, internal documents, and configuration details.
I search for the domain and the subdomains with a set of keywords. The keywords include password, config, internal, admin, and the application name. The results reveal pages that the organization did not intend to share.
The search engine cache can also contain the file names that I need. A cached page may link to a backup file or a log file that is no longer linked from the live application. The file may still exist on the server.
The search results are a hint, not a finding. I verify the content by requesting the live file. If the file is no longer accessible, the leak is historical and the impact is lower.
Source maps
Source maps are files that map the minified JavaScript back to the original source. They are used for debugging, and they are often left in the production deployment. A source map can reveal the original code, including internal API calls and hardcoded values.
The source map is usually referenced at the end of the JavaScript file. I look for the sourceMappingURL comment and request the map file. The map file contains the original source code.
The original source is easier to read than the minified version. I search the source for the same keywords that I use for the repository history. The source can reveal the backend endpoints and the data structures.
The source map is not always a security issue. If the code does not contain secrets, the map is a minor information disclosure. If the code contains internal details, the impact is higher.
Impact assessment
The impact of an information leak depends on what the file contains. A file with a database password has a higher impact than a file with a welcome message. I assess the content before I assign a severity.
The impact also depends on the access that the file grants. A cloud credential that can access the production account is critical. A documentation file that describes the architecture is medium. A backup file with customer data is high.
The impact assessment should include the validation. I test the credential with the least intrusive request and record the result. The result turns a suspected leak into a confirmed finding.
The report should separate the leak from the impact. The developer needs to know where the file is, what it contains, and what the attacker could do with it.
Why I record the negative results
The negative results are part of the investigation. When I check a path and find nothing, I write down the request and the response. The note prevents me from checking the same path again and helps me see which locations the application actually exposes. The negative results also make the report more honest. I can say that I checked the common backup locations, the editor artifacts, and the configuration files, and I can show what I checked. That evidence is as important as the finding itself.
Common mistakes I make
My biggest mistake is looking for secrets only in the current version of the code. The history and the backups contain more secrets than the current files. My second mistake is validating a secret with a destructive request. The validation should be read-only and safe. My third mistake is including the full secret in the report.
The fourth mistake is ignoring the impact of cloud credentials. A database password is bad, but a cloud service account can be much worse. The fifth mistake is treating every sensitive-looking string as a finding. Some strings are placeholders or test values, and I need to validate them before reporting.
My quick checklist
- Check
/.git/HEADand/.git/configfor exposed repositories. - Download and search the repository history for secrets.
- Look for backup files and database dumps in the web root.
- Check editor artifacts and directory listing files.
- Read configuration files and cloud credential files.
- Search logs, documentation, source maps, and JavaScript bundles.
- Validate secrets with the least intrusive request.
- Redact secrets and report the impact.
What I would do next time
Next time I want to build the file-name candidates from the application's own patterns before I start brute force. The pattern tells me what the developers are likely to have left behind. I also want to spend more time on the repository history, because that is where the most interesting secrets hide. Information leak hunting is not about finding one file. It is about finding the file that opens the next door.