DEV Community

jeffrey
jeffrey

Posted on

Protecting access tokens on developer workstations: the attack path that skips your CI controls

Protecting access tokens on developer workstations: the attack path that skips your CI controls

The gap between build and desktop

Teams that harden their build pipeline often leave the workstation as the weakest credential store. A developer's machine holds an SSH private key, a cloud CLI profile with a refresh token, session cookies for the source host, package registry tokens and often a browser profile with long-lived sessions for several services. A single malicious dependency installed during a local test run reaches all of them, because it runs with the developer's privileges in the same filesystem.

The consequence is that the organisation's change history can be modified without ever touching the build system, which is the boundary the compliance story usually describes.

How tokens end up readable

Three storage patterns account for most exposure. A credential written into a dotfile in the home directory, which is world readable on a default installation. A credential cached by a command-line tool in a plaintext file, which many tools use when the platform keychain is unavailable or disabled in a headless session. A token exported into an environment variable in a shell profile, which is then inherited by every process started from that shell, including a build step run locally.

Long-lived credentials amplify it. A refresh token that does not expire needs one moment of access to become permanent access, while a short-lived token bounds the theft to its remaining lifetime. RFC 9700 codifies current best practice for OAuth 2.0 clients and is the reference for scope and lifetime decisions.

Changes that reduce the value of a stolen token

Move storage to the platform keychain or an equivalent credential store, and configure command-line tools to use it rather than a plaintext fallback. Where a tool offers a credential helper, use it, because it keeps the token out of dotfiles and out of the process environment.

Shorten lifetimes and use scoped credentials. A cloud CLI profile can be replaced with a short-lived session obtained through an identity-aware broker, and a source host token can be narrowed to the repositories the developer actually needs. Any credential that is currently unlimited should be documented as such with a reason.

Isolate the development environment. A container or a virtual machine that mounts only the repository removes the filesystem access that turns a malicious dependency into a credential theft. It also makes the environment reproducible, which is a separate benefit.

Centralise the inventory. Each workstation holds credentials for several services, and a register that lists which credential types are present and who can revoke them is what makes a compromise containable. OWASP treats centralisation and rotation as core practices for a reason.

Detecting the path

Watch for local processes that read multiple credential files in a short window, for source host tokens used from a new address, and for repository changes authored from addresses that do not match the developer's usual network. None of these has a high base rate on a normal workstation, which makes them usable as signals.

References

  1. RFC 9700, Best Current Practice for OAuth 2.0 Security. https://www.rfc-editor.org/rfc/rfc9700.html
  2. Secrets Management Cheat Sheet, OWASP. https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
  3. ssh-keygen(1), OpenBSD manual pages. https://man.openbsd.org/ssh-keygen.1

Top comments (0)