In a Go application, load secrets once at startup from a central store, hold them in a small type that refuses to print itself, never bake them into binaries or images, and keep each credential narrow and rotatable. Go's static binaries make leaks easy to ship, so plan the path before the first deploy.
The principles below come from the OWASP Secrets Management Cheat Sheet. The Go code advice is design guidance, not a library recommendation.
Why do Go secrets leak?
Go compiles to one static binary, which tempts people to embed config. Strings in a binary can be read with common tools, so a key compiled in is a key published to anyone who gets the file. Other usual leaks: a config struct printed with a verbose format verb, an error that wraps a connection string, an HTTP client debug dump with an Authorization header, and a Dockerfile that copies a credentials file into a layer.
OWASP's container advice is to inject secrets at deployment time, through mounted files or a runtime fetch, not at build time.
What does a safe loading pattern look like?
Authenticate to your secrets store with the workload's own identity, read what you need in main, and pass values to the components that use them. Do not read secrets from deep inside business code, because that scatters access and makes audits hard. Fail at startup if something required is missing. A service that crashes loudly at boot is better than one that quietly runs with an empty password.
Write a tiny type for secret values, with a String method that returns a fixed placeholder, and a separate explicit method to reveal the value at the one place it is used. Because formatting verbs call String, an accidental log line then prints the placeholder. Add the same placeholder behaviour for JSON encoding so a struct dumped into a response or a log does not expose it.
What about environment variables?
OWASP says to avoid them where possible because they are widely visible. In Go that means os.Environ shows everything to the process, child processes inherit it, and crash tooling may capture it. If you must use them, read and clear them at startup, and do not pass the full environment to subprocesses you start.
How do you scope, rotate and audit?
OWASP's guidance: give each secret the narrowest permissions, prefer short-lived dynamic credentials, automate rotation, and log who requested secrets and when they were used. Note that restarting an application does not revoke a credential. Design your service so it can pick up a rotated secret, either by re-reading on a timer or on a signal, because a service that needs a redeploy to rotate will not rotate often.
How do you catch mistakes in CI?
Add secret scanning to pre-commit and CI. OWASP recommends detection tools in development and CI so leaks are caught early. Also scan built images and the final binary, not only source, since a value can arrive through a build argument.
Treat CI as production: no big shared secrets, no secrets available to pull requests from forks, and no output that echoes them.
What to do when a key leaks
- Revoke it first, then rotate through an automated process.
- Remove it from code, logs, images and artifacts.
- Check access logs for use you did not make.
- Document who was told and what changed.
What to do now
- Search source, history and images for keys and tokens.
- Add a secret type with a redacting String method and use it for every credential.
- Load secrets in main from a store, and fail fast when absent.
- Stop passing secrets as build arguments or copying them into images.
- Enable rotation and make the service reload credentials.
- Add secret scanning to CI.
Safeguard has a secrets scanning capability, with a demo at /demos/secrets-scanning that shows how findings look.
Quick check
Is it safe to embed a key in a Go binary?
No. Strings in a binary can be extracted. Inject secrets at deployment time instead.
Does restarting my service revoke a leaked credential?
No. OWASP notes that revocation comes from lease expiry or an explicit call to the provider.
Sources
Last reviewed: 18 October 2026.