// Engineering Log

Secure Development: Part 2 — Secrets in Code

Published on 2026-09-22

// Fast route

This article belongs to the topic Security and protection.

A secret is any data that grants access to a resource: a database password, a payment system or cloud API key, a bot token, a private SSH key. If such a secret ends up in Git, removing it in the next commit does not fix anything: Git stores the entire history, and the old version of the file is available to anyone who has a copy of the repository. Automated scanners continuously scan public repositories, so a key committed to a public commit should be considered compromised immediately.

If a secret has already leaked

Order of actions is more important than tools:

  1. Revoke or rotate the secret with the provider: create a new key, deactivate the old one, change the database password. This is the only step that truly closes access.
  2. Check the service access logs related to the key: whether someone unauthorized has used it.
  3. Rotate related credentials. If a password that was used in multiple places leaked, change it everywhere.
  4. Only after that, clean the repository history. The Git project recommends using git filter-repo for this instead of the deprecated git filter-branch:
bash
# remove file from entire history
git filter-repo --path config/secrets.yml --invert-paths

# replace strings from replacements.txt across all commits
git filter-repo --replace-text replacements.txt

After rewriting history you need to force-push to the remote repository, and all contributors must re-clone the project. Copies that have already spread — forks, local clones, CI caches — are not affected by the cleanup. Therefore it does not replace the first step; it only removes traces.

Where to store secrets

  • In development — in a .env file that is listed in .gitignore. Put a .env.example in the repository with variable names and empty values so colleagues know what to fill in.
  • In CI/CD — in the project’s protected variables: masked and protected in GitLab, secrets in GitHub Actions.
  • On servers — in the service environment or in a separate secrets store, but not in code and not in the Docker image.

If .env has already been committed to the repository, simply adding it to .gitignore is not enough: the file must be removed from the index with git rm --cached .env — and, of course, change everything that was in it.

Gitleaks

Gitleaks searches repositories and directories for passwords, keys, and tokens using a set of regular expressions for hundreds of formats. License MIT, current version as of September 2026 — 8.30.1. The author declared the tool completed: new features are no longer added, only security fixes are released, and development continues in a new project, Betterleaks.

Main modes of operation:

bash
gitleaks git -v     # scan the entire history of the current repository
gitleaks dir .      # scan files in the directory without history

The detect and protect commands from older versions are deprecated, although they still work for now.

Check before every commit: pre-commit

The pre-commit framework runs checks automatically on every git commit. Install and hook up Gitleaks:

bash
pip install pre-commit

.pre-commit-config.yaml at the project root:

yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.1
    hooks:
      - id: gitleaks
bash
pre-commit install          # install the hook into the repository
pre-commit run --all-files  # check all files right after installation
pre-commit autoupdate       # update hook versions

If Gitleaks finds a secret, the commit will not proceed. The check can be skipped with the variable SKIP=gitleaks, so the local hook is a convenience for the developer, not a guarantee.

TruffleHog

TruffleHog addresses the same task but can verify findings: for many key types it queries the provider’s API and reports whether the key is active. License AGPL-3.0, current version — 3.97.5.

bash
trufflehog git https://git.example.ru/team/project.git --results=verified

The --results=verified flag leaves only keys confirmed as active in the report. Such findings require immediate key rotation.

Server-side scanning

Since local checks can be disabled, they should be repeated in the pipeline — as the first job, before build and tests. For GitHub Actions, Gitleaks provides a ready-made gitleaks-action; in GitLab CI and Gitea Actions it’s enough to have a job that runs gitleaks git in the project directory. Such a job should stop the pipeline on any finding.

GitHub also has its own protection — push protection. For personal accounts it is enabled by default and prevents pushing a secret to a public repository. Repository-level protection, which works for private projects as well, requires the paid GitHub Secret Protection feature and must be enabled by an administrator.

Common mistakes

  • Deleting the file in a new commit and thinking the problem is solved. The secret remains in the history.
  • Cleaning history instead of rotating the key. Copies of the repository already exist.
  • Printing secrets to CI logs. The command echo $TOKEN for debugging prints the key into the build log; protected variables are masked, but you shouldn’t rely only on that.
  • Passing secrets into a Docker image via ARG or ENV. They are stored in image layers; the correct way is BuildKit secrets.
  • Using the same key for development and production. A leak in the test environment opens access to production.

// Similar task

If you are dealing with something similar

This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.

Article topic

Security and protection

SSL, hardening, access control, service protection, and secure configurations.

Typical tasks behind this topic

  • Set up SSL, certificates, and secure connections
  • Restrict access and close unnecessary entry points
  • Harden server and service configuration

// Next step

If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.

Open services

// Reviews

Related reviews

I came with an expensive request to configure a VPS server, but during the consultation Mikhail suggested a much simpler, more affordable solution. In the end I saved time and money. Mikhail — a true expert who works for the client's result, not for the fee. I recommend him!

I came with an expensive request to configure a VPS server, but during the consultation Mikhail suggested a much simpler and more cost-effective solution. In the end I saved budget and time. Mikhail — a true expert who …

kfhzasorin

VPS setup, server setup

2026-05-12 · ★ 5/5

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply