VYPR
Critical severityNVD Advisory· Published Mar 13, 2026· Updated Mar 13, 2026

Dagu has a Path Traversal via `dagRunId` in Inline DAG Execution

CVE-2026-31886

Description

Dagu is a workflow engine with a built-in Web user interface. Prior to 2.2.4, 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// 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. This vulnerability is fixed in 2.2.4.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Dagu prior to 2.2.4 allows path traversal via the dagRunId parameter in inline DAG execution, leading to deletion of system temporary directory and denial of service.

Vulnerability

Overview

CVE-2026-31886 is a path traversal vulnerability in the Dagu workflow engine (versions prior to 2.2.4). The vulnerability resides in the loadInlineDAG() function within dagruns.go [2]. When handling inline DAG execution requests, the dagRunId parameter is passed directly to Go's filepath.Join without validation. Because filepath.Join lexically resolves .. segments, an attacker can supply a value like .. to redirect the constructed temporary directory path outside the intended /tmp// location [1].

Exploitation

The attack requires network access to the inline DAG execution endpoint. No authentication is needed if the default (no auth) configuration is used, but the flaw exists regardless of authentication [2]. By setting dagRunId to .., the resolved path becomes the system temporary directory (/tmp on Linux). A deferred cleanup function then calls os.RemoveAll on this directory unconditionally when the HTTP handler returns [2].

Impact

On non-root deployments, os.RemoveAll("/tmp") deletes all files in /tmp owned by the dagu process user, disrupting concurrent dagu runs using temporary files. On root or Docker deployments, the entire contents of /tmp are removed, causing a system-wide denial of service [1][2].

Mitigation

The vulnerability is fixed in Dagu version 2.2.4 [1][2][3]. Users should upgrade immediately. There are no workarounds provided; the fix involves adding input validation to the dagRunId parameter [4].

AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/dagu-org/daguGo
<= 2.2.4

Affected products

2
  • Dagu Org/Dagullm-fuzzy2 versions
    <2.2.4+ 1 more
    • (no CPE)range: <2.2.4
    • (no CPE)range: < 2.2.4

Patches

1
12c2e5395bd9

refactor: use SeedReferences return value and consolidate reference prompt section

https://github.com/dagu-org/daguYota HamadaMar 10, 2026via ghsa
2 files changed · +6 9
  • internal/agent/system_prompt.txt+2 5 modified
    @@ -276,9 +276,9 @@ Rules:
     </memory_management>
     {{end}}
     
    +<reference>
     {{if .ReferencesDir}}
    -<builtin_knowledge>
    -Built-in reference documents are available at {{.ReferencesDir}}/. Use `read` to load them when you need detailed information beyond what `dagu schema` provides.
    +Reference documents are available at {{.ReferencesDir}}/. Use `read` to load them when you need details beyond what `dagu schema` provides.
     
     Available references:
     - `schema.md` — Complete DAG YAML schema (top-level and step-level fields)
    @@ -292,10 +292,7 @@ Load a reference when:
     - A user asks about a specific executor, CLI command, or env var and `dagu schema` doesn't cover the detail
     - You need to write a DAG that uses coding agents (claude -p, codex exec, gemini -p, etc.)
     - You want to double-check a pitfall before authoring a DAG
    -</builtin_knowledge>
     {{end}}
    -
    -<reference>
     Use `dagu schema` and `dagu example` via bash to look up DAG YAML structure and see examples:
     - `dagu schema dag` — root-level DAG fields
     - `dagu schema dag steps` — step properties
    
  • internal/service/frontend/server.go+4 4 modified
    @@ -180,7 +180,7 @@ func NewServer(ctx context.Context, cfg *config.Config, dr exec.DAGStore, drs ex
     	}
     
     	// Seed built-in knowledge references to data dir (not git-synced).
    -	fileagentskill.SeedReferences(
    +	referencesDir := fileagentskill.SeedReferences(
     		filepath.Join(cfg.Paths.DataDir, "agent", "references"),
     	)
     
    @@ -318,7 +318,7 @@ func NewServer(ctx context.Context, cfg *config.Config, dr exec.DAGStore, drs ex
     
     	var agentAPI *agent.API
     	if agentConfigStore != nil {
    -		agentAPI, err = initAgentAPI(ctx, agentConfigStore, agentModelStore, agentSkillStore, agentSoulStore, &cfg.Paths, cfg.Server.Session.MaxPerUser, dr, auditSvc, memoryStore, newRemoteNodeAdapter(remoteNodeResolver))
    +		agentAPI, err = initAgentAPI(ctx, agentConfigStore, agentModelStore, agentSkillStore, agentSoulStore, &cfg.Paths, referencesDir, cfg.Server.Session.MaxPerUser, dr, auditSvc, memoryStore, newRemoteNodeAdapter(remoteNodeResolver))
     		if err != nil {
     			logger.Warn(ctx, "Failed to initialize agent API", tag.Error(err))
     		}
    @@ -649,7 +649,7 @@ func autoEnableExampleSkills(ctx context.Context, configStore agent.ConfigStore)
     
     // initAgentAPI creates and returns an agent API.
     // The API uses the config store to check enabled status and resolve providers via the model store.
    -func initAgentAPI(ctx context.Context, store *fileagentconfig.Store, modelStore agent.ModelStore, skillStore agent.SkillStore, soulStore agent.SoulStore, paths *config.PathsConfig, sessionMaxPerUser int, dagStore exec.DAGStore, auditSvc *audit.Service, memoryStore agent.MemoryStore, remoteResolver agent.RemoteNodeResolver) (*agent.API, error) {
    +func initAgentAPI(ctx context.Context, store *fileagentconfig.Store, modelStore agent.ModelStore, skillStore agent.SkillStore, soulStore agent.SoulStore, paths *config.PathsConfig, referencesDir string, sessionMaxPerUser int, dagStore exec.DAGStore, auditSvc *audit.Service, memoryStore agent.MemoryStore, remoteResolver agent.RemoteNodeResolver) (*agent.API, error) {
     	sessStore, err := filesession.New(paths.SessionsDir, filesession.WithMaxPerUser(sessionMaxPerUser))
     	if err != nil {
     		logger.Warn(ctx, "Failed to create session store, persistence disabled", tag.Error(err))
    @@ -681,7 +681,7 @@ func initAgentAPI(ctx context.Context, store *fileagentconfig.Store, modelStore
     			ConfigFile:     paths.ConfigFileUsed,
     			WorkingDir:     paths.DAGsDir,
     			BaseConfigFile: paths.BaseConfig,
    -			ReferencesDir:  filepath.Join(paths.DataDir, "agent", "references"),
    +			ReferencesDir:  referencesDir,
     		},
     	})
     
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.