🛡️ CVE-2026-31886 — dagu

🔴 CVSS 9.5 — Critical ⚠️ Exploit Public CWE-22 NVD
9.5
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Dagu: Path Traversal via dagRunId in Inline DAG Execution

1. Vulnerability Summary

The dagRunId request field accepted by the inline DAG execution endpoints is passed directly into filepath.Join to construct a temporary directory path without any format validation. Go's filepath.Join resolves .. segments lexically, so a caller can supply a value such as ".." to redirect the computed directory outside the intended /tmp/<name>/<id> path. A deferred cleanup function that calls os.RemoveAll on that directory then runs unconditionally when the HTTP handler returns, deleting whatever directory the traversal resolved to.

With dagRunId set to "..", the resolved directory is the system temporary directory (/tmp on Linux). On non-root deployments, os.RemoveAll("/tmp") removes all files in /tmp owned by the dagu process user, disrupting every concurrent dagu run that has live temp files. On root or Docker deployments, the call removes the entire contents of /tmp, causing a system-wide denial of service.

2. This Is Not a Duplicate of Existing Advisories

Two security advisories are already published for dagu. This vulnerability is distinct from both.

GHSA-6qr9-g2xw-cw92 fixed the fact that the default authentication mode was none, allowing unauthenticated access to the inline execution endpoint. That advisory covers authentication bypass. The dagRunId path traversal described here is a separate input-validation flaw in loadInlineDAG() that exists regardless of whether authentication is required and was not addressed by that fix.

CVE-2026-27598 fixed a path traversal in the DAG creation endpoint (POST /api/v1/dags) via the name field. The fix added filepath.Base() and a base-directory prefix check inside generateFilePath(). That fix applies only to generateFilePath() in dags.go. The function loadInlineDAG() in dagruns.go has no equivalent guard on its dagRunID argument and was not part of that patch.

3. Vulnerable Code

File: internal/service/frontend/api/v1/dagruns.go

The loadInlineDAG function (lines 202-267) constructs the temp directory at line 234:

```go

tmpDir := filepath.Join(os.TempDir(), nameHint, dagRunID)

```

dagRunID is user-supplied. No validation of the value occurs before this line. The cleanup closure is then registered:

```go

cleanup := func() {

_ = os.RemoveAll(tmpDir)

}

```

In ExecuteDAGRunFromSpec (lines 52-119), the cleanup is deferred unconditionally:

```go

dag, cleanup, err := a.loadInlineDAG(ctx, request.Body.Spec, request.Body.Name, dagRunId)

if err != nil {

return nil, err

}

defer cleanup() // registered after loadInlineDAG succeeds; fires on all subsequent return paths

```

The same pattern appears in EnqueueDAGRunFromSpec (lines 122-200), line 160:

```go

defer cleanup()

```

Why the OpenAPI schema pattern does not prevent this:

The DAGRunId schema in api/v1/api.yaml (line 5738) declares:

```yaml

pattern: "^[a-zA-Z0-9_-]+$"

```

This pattern excludes . and /, which would block path traversal values. However, enforcement of that pattern depends on the OpenAPI validator middleware, which is only activated when StrictValidation is true. That setting is defined in internal/cmn/config/config.go:

```go

StrictValidation bool

```

It is not present in the Definition struct (definition.go) and carries no mapstructure tag, which means viper/mapstructure can never populate it from a YAML configuration file; it therefore cannot be set in the config loader (loader.go) and its value is always the Go zero value for bool, which is false. The loader test at line 165 of loader_test.go confirms that StrictValidation is false even after loading a comprehensive configuration file that exercises every configurable option — because there is no mechanism by which it could ever be true. The validator middleware is never registered for any standard dagu deployment.

The file dagruns.go defines a sanitizeFilename helper at line 36 that replaces characters outside [a-zA-Z0-9._-] with underscores. This function is called when constructing log filenames (lines 422, 566, 1127, and 1211) and is never applied to dagRunID before the filepath.Join call. No validation or sanitization of dagRunID for path separator characters exists anywhere in the request-to-filepath.Join pipeline.

4. Attack Conditions

  • The attacker must be authenticated with a role of operator, developer, manager, or admin (any role for which CanExecute() returns true).
  • The server permission PermissionRunDAGs must be enabled. This is the default (true as set in loader.go lines 353-356).
  • On dagu versions 1.30.3 and earlier, where the default authentication mode was none, no authentication is required at all.

5. Attack Scenario

Step 1: Authenticate

```bash

TOKEN=$(curl -s -X POST http://TARGET:8080/api/v1/auth/login \

-H "Content-Type: application/json" \

-d '{"u

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality low, integrity low, availability high.

Weakness class

CVE-2026-31886 is classified as CWE-22: Path Traversal. A file path built from user input is not confined to the intended directory, letting an attacker reach files elsewhere on the filesystem.

Affected software

CVE-2026-31886 is recorded against 2 packages.

  • dagu (fixed in 2.2.4)
  • github.com/dagu-org/dagu

Timeline and source

Published on 13 March 2026 and last revised on 17 June 2026. A public exploit is known to exist, which raises the urgency of patching considerably. A vendor advisory or fix has been published. Record sourced from NVD.

References

github.com
github.com

Details

Severity CRITICAL
CVSS Score 9.5
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:H
CWE CWE-22
Public Exploit ⚠️ Yes
Source NVD
Published 2026-03-13
Updated 2026-08-12
Modified 2026-06-17

Affected Packages

Software From version Fixed in
dagu 2.2.4
github.com/dagu-org/dagu

Similar Threats

Exploit Protection

Are you running dagu?

CVE-2026-31886 carries CVSS 9.5 Critical rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2026-31886 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.