Jul 14, 2026·6 min read·3 visits
Woodpecker CI server used an unsafe metadata append operation, allowing authenticated agents to spoof their identity and impersonate any other registered agent.
A critical authentication bypass vulnerability in Woodpecker CI allows authenticated agents to impersonate other agents by injecting spoofed agent_id values into gRPC metadata. This flaw is caused by the use of md.Append instead of md.Set on the server-side RPC authorizer.
Woodpecker CI utilizes a central server architecture that interacts with multiple execution agents to process build pipelines. These runner agents communicate with the server via gRPC bidirectional communication. The agent authorization model relies on cryptographically signed JSON Web Tokens (JWT) issued to each registered agent to establish a trusted channel.
From version 3.0.0 and prior to version 3.14.1, Woodpecker CI contains an authentication bypass flaw in its gRPC authorization interceptor. The flaw permits an authenticated agent to impersonate any other agent registered on the same instance. This weakness is categorized under CWE-290 (Authentication Bypass by Spoofing) and CWE-639 (Authorization Bypass Through User-Controlled Key).
An attacker who has compromised or legitimately obtained access to a single low-privileged agent can manipulate metadata parameters to assume the identity of more privileged agents. This cross-tenant impersonation bypasses logical isolation boundaries in multi-tenant Woodpecker deployments. The impact includes unauthorized task interception, source code leakage, and execution of arbitrary workflows within separate tenant environments.
The root cause of the vulnerability resides in the discrepancy between identity validation and transport-layer metadata serialization in the gRPC interceptor logic located at server/rpc/authorizer.go. When an agent initiates a gRPC connection, the server validates the agent's JWT. Upon successful cryptographic verification, the handler extracts the authorized agent identity value (claims.AgentID).
The server attempts to inject this verified identity into the gRPC incoming context to ensure downstream handlers can access the authenticated agent ID. To achieve this, the authorizer called md.Append("agent_id", fmt.Sprintf("%d", claims.AgentID)). The md.Append function appends values to the existing list of elements under the key agent_id rather than replacing the key's value.
Because gRPC allows clients to supply arbitrary metadata headers, a malicious agent can pre-populate the request headers with an agent_id key set to a target agent's identifier. The md.Append call appends the true, validated agent ID to the end of the metadata slice, resulting in a slice containing both the spoofed and the real IDs. When downstream processes query the context using indexing or single-value retrieval methods, they fetch the first element of the slice, which corresponds to the attacker-supplied, spoofed agent ID.
The process of metadata parsing and the resultant security bypass are illustrated in the following diagram:
The vulnerability was fixed in pull requests #6567 and #6569. The initial patch resolves the metadata collection issue by replacing the append behavior with a strict overwrite function. This ensures that any input provided by the client under the key agent_id is discarded and replaced with the cryptographically validated ID from the JWT.
Review the code changes introduced in server/rpc/authorizer.go below:
// BEFORE THE PATCH
func (a *Authorizer) authorize(ctx context.Context, fullMethod string) (context.Context, error) {
// ... validation logic ...
claims, err := a.verifyToken(token)
if err != nil {
return ctx, status.Errorf(codes.Unauthenticated, "access token is invalid: %v", err)
}
// Unsafe append action that allows client-supplied values to persist
md.Append("agent_id", fmt.Sprintf("%d", claims.AgentID))
return metadata.NewIncomingContext(ctx, md), nil
}
// AFTER THE PATCH
func (a *Authorizer) authorize(ctx context.Context, fullMethod string) (context.Context, error) {
// ... validation logic ...
claims, err := a.verifyToken(token)
if err != nil {
return ctx, status.Errorf(codes.Unauthenticated, "access token is invalid: %v", err)
}
// Overwrites any client-supplied 'agent_id' with the verified claims identity
md.Set("agent_id", fmt.Sprintf("%d", claims.AgentID))
return metadata.NewIncomingContext(ctx, md), nil
}A second pull request, #6569, established a deeper structural separation. It migrated context identity propagation away from gRPC transport metadata keys entirely. By utilizing private Go context keys, the updated code prevents any client-supplied transport metadata from influencing the authentication state parsed by downstream business logic handlers.
To execute the impersonation attack, an attacker must satisfy specific prerequisites. First, they must obtain legitimate credentials for an agent authorized to communicate with the Woodpecker server. In multi-tenant environments where organization-level or user-level agent registration is enabled, an attacker can register a restricted agent to establish this initial foothold.
Once the attacker-controlled agent is registered, the attacker modifies the agent binary or uses a custom gRPC client implementation. The custom client establishes a gRPC connection to the Woodpecker server, presenting its valid JWT in the authorization header. Simultaneously, the client inserts an HTTP/2 header containing the key agent_id and the numeric identifier of the target agent, such as 1 for the default system agent.
When the server processes the connection, the authorizer appends the client's verified agent ID to the end of the agent_id metadata slice. Because the server parses metadata using index zero or a method that returns the first available element, the server treats the request as originating from the target agent. The attacker-controlled agent then receives and executes pipelines designated for the impersonated agent, harvesting credentials and environment secrets associated with those tasks.
The security impact of CVE-2026-50141 is high because it compromises the logical isolation of the CI/CD pipeline infrastructure. In environments where multiple teams share a single Woodpecker CI control plane, a compromise of one tenant's agent leads directly to the potential compromise of all other tenants. The CVSS v4.0 base score is calculated as 7.1, indicating high severity.
An attacker who successfully impersonates a highly privileged agent can poll the server for pending execution tasks. By retrieving these build tasks, the malicious agent receives the full build context. This context includes environment variables, secret keys, repository access tokens, and deployment credentials stored within the target projects.
Additionally, the attacker can hijack build execution. The attacker can return falsified build statuses, alter generated binaries or container images during the build process, and inject backdoors into downstream deployment pipelines. This compromises the integrity of the software supply chain without triggering immediate infrastructure alerts.
The primary remediation for this vulnerability is to upgrade the Woodpecker CI deployment. Both the Woodpecker server and agent components must be updated to version 3.14.1 or higher. This release addresses the vulnerability by applying the md.Set metadata configuration and introducing context-level key propagation to prevent header injection attacks.
If immediate updates are not possible, administrators should mitigate exposure by disabling user-level agent registrations. By setting the environment variable WOODPECKER_DISABLE_USER_AGENT_REGISTRATION=true on the Woodpecker server, administrators restrict the registration of new agents to system-level administrators. This prevents untrusted users from establishing the initial authenticated session required to execute the exploit.
Additionally, security teams should review active agents within the database and remove any non-system or unauthorized registrations. Analyzing gRPC transport logs for occurrences of duplicated or client-provided agent_id headers is recommended to detect historical exploitation attempts.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Woodpecker CI woodpecker-ci | >= 3.0.0, < 3.14.1 | 3.14.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-290, CWE-639 |
| Attack Vector | Network |
| CVSS v4.0 Score | 7.1 (High) |
| Exploit Status | PoC (Proof of Concept) |
| Affected Component | gRPC Authorization Interceptor (server/rpc/authorizer.go) |
| Fixed Version | v3.14.1 |
The software records or uses communication channel or message sender identity information that is incorrect, allowing attackers to bypass authentication controls and impersonate legitimate entities.
A technical analysis of CVE-2025-61670, a memory leak vulnerability in Wasmtime's C and C++ API bindings. The issue stems from a refactoring in version 37.0.0 that transitioned garbage-collected reference tracking to host heap-allocated OwnedRooted types without updating FFI ownership semantics.
Fedify, a TypeScript framework for ActivityPub servers, implemented incomplete public URL validation inside the @fedify/fedify and @fedify/vocab-runtime libraries. The validator only blocked basic RFC 1918 networks, standard loopbacks, and link-local addresses, failing to restrict Carrier-Grade NAT (CGNAT), benchmarking, reserved, or IPv6 transition addresses. Consequently, unauthenticated remote attackers can bypass SSRF filters to access sensitive internal microservices and endpoints.
CVE-2026-54250 is a path traversal vulnerability in K3s, a lightweight Kubernetes distribution. The flaw exists within the etcd snapshot decompression functionality, allowing administrative users to write arbitrary files to the host filesystem via a maliciously crafted ZIP archive. Due to the high privilege level of the K3s process, this can result in total host compromise.
A Denial of Service vulnerability exists in the json-repair Python library due to an unconstrained loop during JSON Schema reference resolution. By submitting a circular JSON Schema, an attacker can trigger infinite recursion, causing 100 percent CPU exhaustion. Because this package is heavily utilized in LLM data-processing pipelines, this flaw presents a substantial threat to application availability.
A cryptographic validation flaw in the Apple App Store Server Python Library allows an attacker to bypass Online Certificate Status Protocol (OCSP) revocation checks. When online verification is enabled, the library fails to validate temporal constraints on OCSP response payloads. This flaw enables network-positioned adversaries to perform OCSP replay attacks, forcing the application to accept JSON Web Signatures (JWS) signed by revoked certificates.
The DIRAC PilotManager component contains combined security weaknesses: a SQL injection vulnerability (CWE-89) in the PilotAgentsDB database interaction layer, and an improper access control configuration (CWE-284) within the default authorization structure. A low-privilege authenticated attacker can bypass intended authorization checks to run administrative commands, manipulate grid job tracking records, and execute arbitrary SQL statements against the backend database.