By NHI Mgmt Group Editorial TeamDomain: Breaches & IncidentsSource: CorgeaPublished May 20, 2026

TL;DR: Socket’s analysis of a long-running Go module typosquat shows how a one-character package mismatch let a malicious decimal library preserve the expected API while executing a DNS-based command backdoor at import time, even in builds that continued to pass arithmetic tests. The lesson is that dependency trust now depends on path verification, cache hygiene, and runtime review, not just successful compilation, according to Corgea.


At a glance

What this is: This is an analysis of a Go module typosquat that preserved the decimal library API while hiding a DNS-triggered command execution backdoor in package initialisation.

Why it matters: It matters because IAM, secrets, and build-security teams need to treat dependency import paths, build caches, and service credentials as part of the trust boundary for CI/CD and production systems.

By the numbers:

👉 Read Corgea's analysis of the Go module typosquat and DNS backdoor


Context

Go module typosquats exploit a trust gap that sits between package resolution, code review, and runtime behaviour. A one-character import mistake can pull in a dependency that looks legitimate, compiles cleanly, and still executes attacker-controlled code during package initialisation. For identity and secrets practitioners, that makes the build pipeline itself part of the credential-exposure surface.

The deeper problem is that software supply-chain controls often assume functional tests will expose malicious code. In this case, the copied API preserved normal arithmetic behaviour, so the payload hid outside the business logic. That is a familiar failure pattern in dependency governance: the package behaves correctly enough to pass checks while still violating runtime trust.

For teams running CI/CD, developer workstations, and production Go services, this is a governance issue as much as a code issue. The starting position is not unusual; typosquats, mirrored packages, and stale caches routinely survive long enough to become operational risk.


Key questions

Q: What breaks when a Go typosquat preserves the same API as the real package?

A: Functional tests often still pass, which hides the compromise. The danger is that the malicious code can live in package initialisation or another side effect path, so the application behaves normally enough to avoid suspicion while the attacker gains execution, persistence, or access to secrets.

Q: Why do typosquatted dependencies create identity and secrets risk?

A: Because build systems, CI runners, and production services often run with service accounts, tokens, and registry credentials. If a malicious dependency executes in that context, it can reach non-human identities and the secrets they can use, turning a packaging error into an access-control failure.

Q: How do security teams know if a poisoned dependency is still present?

A: They need to search source control, dependency manifests, module caches, internal mirrors, build logs, and compiled binaries together. One location is not enough, because Go proxies and local caches can preserve the malicious version long after the upstream repository is gone.

Q: What should teams do after a malicious dependency is discovered?

A: Contain the affected endpoints, revoke any credentials that were reachable from those systems, and rebuild trust from known-clean environments. Then review where secrets are stored, not just which package was compromised. If the same workstation holds cloud, SSH, and SaaS credentials, the incident response plan must cover all three identity domains.


Technical breakdown

How a Go typosquat survives functional testing

A typosquat works because package resolution happens before runtime behaviour is examined. If the malicious module preserves the same exported functions and signatures as the legitimate library, unit tests can still pass while the attacker adds hidden code in package initialisation. In Go, init() runs before main() and before callers invoke any library method, so a direct or transitive import is enough to trigger the payload. That makes API compatibility a poor assurance signal when the threat lives outside the nominal library logic.

Practical implication: Treat exact module path verification and dependency allowlisting as control requirements, not optional review steps.

Why DNS TXT records are attractive for covert command channels

DNS TXT lookups are often treated as background infrastructure noise, which gives attackers a low-friction way to retrieve instructions. In this pattern, the compromised package polls a hardcoded hostname, reads TXT responses, and uses them as command targets. Because the channel is decoupled from web proxies and common application telemetry, it can evade controls that focus only on HTTP or outbound API traffic. The result is a quiet command-and-execution loop that lives inside normal build or runtime processes.

Practical implication: Monitor DNS TXT activity from build agents and application hosts, especially when the queried domain is a free dynamic DNS service.

Why Go module proxies and caches extend the blast radius

Go’s module distribution model caches packages for reproducible builds, which helps legitimate teams but also preserves malicious versions after the original repository disappears. That means deleting the upstream GitHub repository does not remove the threat from module proxies, internal mirrors, go.sum files, or local caches. Once a build artifact has been produced, the compromised code can also persist inside compiled binaries. The security problem is therefore lifecycle-wide, not repository-wide.

Practical implication: Search source trees, module caches, internal proxies, and binaries together when you scope a suspected typosquat exposure.


Threat narrative

Attacker objective: The attacker’s objective was to achieve persistent command execution through a trusted dependency and use that access to reach secrets, tooling, or downstream systems.

  1. Entry occurred through a one-character Go module typosquat that impersonated the legitimate decimal library and was fetched by mistake or via a poisoned mirror.
  2. Credential or command access followed when package initialisation queried DNS TXT records and used the returned values as executable commands inside the process.
  3. Impact included covert code execution within CI runners, developer workstations, or production services, with potential access to NHI secrets and build-time credentials.

Read our 52 NHI Breaches Analysis report for a comprehensive view of breaches impacting Non-Human Identities including AI Agents.


NHI Mgmt Group analysis

Dependency trust is now an identity problem, not just a software quality problem. A malicious module that executes at import time can operate inside the same trust zone as CI service accounts, registry tokens, and cloud credentials. That means build governance must treat imported code as a potential NHI consumer and producer, because the package can access identities that traditional application tests never inspect. The practitioner implication is to extend identity governance into dependency admission and build-time execution controls.

Typosquats expose a standing trust assumption that tests routinely validate the attacker’s camouflage. If a malicious library preserves the same API and arithmetic behaviour, functional success becomes evidence of concealment rather than safety. This is a classic software supply-chain failure mode: the controls look healthy because the wrong thing still works. Practitioners should assume that behavioural parity is not a sufficient assurance signal for third-party dependencies.

Cache persistence is the named failure mode here: poisoned dependency artefacts survive long after repository removal. Module proxies, internal mirrors, go.sum files, and compiled binaries can all retain a malicious version even after the upstream source disappears. That persistence changes incident response from repository cleanup to estate-wide provenance review. Teams should treat build infrastructure as a long-lived trust repository, not a transient staging area.

Import-time execution window: the critical control gap is allowing unreviewed code to run before application logic begins. In this case, the malicious payload lived in package initialisation, which means the attack executed before any business function could validate inputs or enforce normal runtime checks. Practitioners should respond by reducing what dependency code can do at import time and by isolating build and runtime identities.

Go dependency governance needs the same lifecycle discipline that mature IAM teams apply to privileged accounts. Exact-path verification, revocation of stale artefacts, and deny rules for known typosquat modules should be managed like access entitlements with ownership and review. In supply-chain terms, a dependency path is an identity assertion about what code is allowed to act inside the environment. The practitioner conclusion is to govern module trust as a controlled entitlement, not a convenience setting.

From our research:

  • The average estimated time to remediate a leaked secret is 27 days, despite 75% of organisations expressing strong confidence in their secrets management capabilities, according to The State of Secrets in AppSec.
  • Only 44% of developers are reported to follow security best practices for secrets management, exposing a significant developer behaviour gap.
  • Forward pivot: For a broader view of how dependency compromise and secret exposure intersect, review The 52 NHI breaches Report and 52 NHI Breaches Analysis.

What this signals

Typosquats force security teams to treat dependency provenance as an identity boundary. Once a package can run at import time, the question is no longer whether the code compiles, but whether the build identity should be allowed to execute it at all. That is why controls aligned to NIST SP 800-53 Rev 5 Security and Privacy Controls and NIST CSF should extend into dependency admission, cache hygiene, and artefact provenance.

The operational signal is clear: teams need detections for unusual DNS TXT lookups, module path mismatches, and secret exposure after build-time compromise. In identity terms, the trust decision is happening before the workload ever starts. For practitioners, that means build systems, service accounts, and package mirrors now belong in the same governance conversation as runtime least privilege.

Import-time execution window: this pattern creates a narrow but decisive control gap between dependency resolution and application startup. If malicious code can execute before normal business logic, conventional application-layer controls arrive too late. The practical response is to verify provenance earlier in the pipeline and to keep high-trust build identities isolated from secrets they do not need.


For practitioners

  • Enforce exact-path module allowlisting Block github.com/shopsprint/decimal explicitly and require code owners to approve any new third-party Go module path before it enters go.mod or a mirror.
  • Sweep caches, mirrors, and build outputs Search go.sum, $GOMODCACHE, internal proxies, and compiled binaries for the typosquat path, then purge retained artefacts from every environment that built or ran it.
  • Rotate secrets used by build identities Rotate Git credentials, SSH keys, cloud tokens, registry credentials, and CI/CD service account secrets available to any host that executed the malicious package.
  • Alert on DNS TXT lookups from build hosts Create detections for recurring TXT queries to freemyip.com or similar dynamic DNS infrastructure from CI runners, developer workstations, and production services.
  • Require provenance checks beyond test success Add dependency provenance review, checksum validation, and package-path verification to release gates so API-compatible typosquats fail before merge.

Key takeaways

  • A one-character Go typosquat can look functionally correct while still running attacker-controlled code at import time.
  • The impact extends beyond software integrity because CI runners, developer workstations, and production binaries can expose service-account secrets and other NHI credentials.
  • The fastest containment path is to revoke the bad module path, purge retained artefacts, and rotate every credential reachable from the compromised build identity.

Standards & Framework Alignment

This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.

MITRE ATT&CK address the attack surface, NIST CSF 2.0, NIST SP 800-53 Rev 5 and CIS Controls v8 set the technical controls, and ISO/IEC 27001:2022 define the regulatory obligations.

FrameworkControl / ReferenceRelevance
MITRE ATT&CKTA0006 , Credential Access; TA0002 , ExecutionThe backdoor uses import-time execution and can reach secrets through compromised build identities.
NIST CSF 2.0PR.AC-1Import path trust and build identity control align with access control and provenance governance.
NIST SP 800-53 Rev 5IA-5Compromised build credentials and exposed secrets point directly to authenticator management.
CIS Controls v8CIS-5 , Account ManagementBuild and service accounts should be governed like any other privileged identity.
ISO/IEC 27001:2022A.5.15Access control is relevant where poisoned artefacts and build identities expand trust boundaries.

Map build-time compromise to execution and credential-access tactics, then block untrusted modules before runtime.


Key terms

  • Go Module Typosquat: A Go module typosquat is a malicious package name that differs by a small typing error from a legitimate dependency. It relies on human mistakes or compromised mirrors to divert imports into attacker-controlled code while preserving enough compatibility to avoid obvious functional failure.
  • Import-time execution: Import-time execution is code that runs when a Python module is loaded rather than when a user deliberately calls a function. That behaviour matters in security reviews because it can trigger secret access, network calls, or persistence before an application has meaningfully started operating.
  • Dependency Provenance: Evidence that a package release came from the expected source, build pipeline, and repository state. Provenance matters because version numbers alone do not prove trust, and malicious actors can use legitimate-looking releases to hide harmful code.
  • Build identity: The set of credentials, tokens, keys, and permissions used by CI/CD systems, runners, and developer tooling. Build identity is often overlooked, yet it can expose secrets, alter repositories, and propagate compromise into downstream software if not tightly scoped and monitored.

What's in the full analysis

Corgea's full analysis covers the operational detail this post intentionally leaves for the source:

  • The exact malicious module artefact, version history, and indicator set that support repository and cache hunting.
  • The full import-time payload structure, including the DNS TXT command channel and execution loop.
  • Practical triage guidance for locating the package in go.sum, module mirrors, and compiled binaries.
  • Remediation actions for rebuilds, cache cleanup, and secret rotation across affected service identities.

👉 Corgea's full post covers the attack chain, indicators of compromise, and remediation steps for affected Go environments.

Deepen your knowledge

NHI Foundation Level course, the industry's only accredited NHI security programme, covers NHI governance, machine identity security, secrets management, and identity lifecycle control. It helps practitioners connect build, runtime, and access governance across modern security programmes.
NHIMG Editorial Note
Published by the NHIMG editorial team on August 21, 2026.
NHI Mgmt Group — the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org