CVE-2026-31817: Github.com/OliveTin/OliveTin OliveTin's Unsafe Parsing Of UniqueTrackingId Vulnerability

HIGH
Advisory Identifier: GHSA-364q-w7vh-vhpc
CVSS 8.5
CWE-22
Published
Advisory Summary

CVE-2026-31817 is a HIGH (CVSS 8.5) olivetin's unsafe parsing of uniquetrackingid vulnerability (CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')) affecting Github.com/OliveTin/OliveTin libraries in the Go ecosystem. The issue involves olivetin's unsafe parsing of uniquetrackingid can be used to write files. Remediation is available by upgrading affected packages to version 0.0.0-20260309102040-b03af0e2eca3.

CVE-2026-31817 at a Glance

CVE Identifier CVE-2026-31817
GHSA Identifier GHSA-364q-w7vh-vhpc
Severity HIGH
CVSS v3.1 Base Score 8.5
CWE Classification CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Affected Product Github.com/OliveTin/OliveTin
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 8.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality None (C:N)
Integrity High (I:H)
Availability Low (A:L)

How to Fix CVE-2026-31817

To remediate this vulnerability, upgrade all affected Github.com/OliveTin/OliveTin dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/OliveTin/OliveTin fixed: 0.0.0-20260309102040-b03af0e2eca3
Upgrade github.com/OliveTin/OliveTin to 0.0.0-20260309102040-b03af0e2eca3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/OliveTin/OliveTin

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-31817, inspect your project dependencies for Github.com/OliveTin/OliveTin:

inspect dependencies for github.com/OliveTin/OliveTin

Analyze the terminal output to locate any version of Github.com/OliveTin/OliveTin in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.0.0-20260309102040-b03af0e2eca3), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'), where the product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory. In Github.com/OliveTin/OliveTin, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

When the `saveLogs` feature is enabled, OliveTin persists execution log entries to disk. The filename used for these log files is constructed in part from the user-supplied `UniqueTrackingId` field in the `StartAction` API request. This value is not validated or sanitized before being used in a file path, allowing an attacker to use directory traversal sequences (e.g., `../../../`) to write files to arbitrary locations on the filesystem. ### Affected Code **Entry point — `service/internal/api/api.go` (line 130):** The `UniqueTrackingId` from the API request is passed directly to the executor without validation: ```go execReq := executor.ExecutionRequest{ Binding: pair, TrackingID: req.Msg.UniqueTrackingId, // user-controlled, no validation // ... } ``` **Tracking ID accepted as-is — `service/internal/executor/executor.go` (lines 508–512):** The tracking ID is only replaced with a UUID if it is empty or a duplicate. Any other string, including one containing path separators, is accepted: ```go _, isDuplicate := e.GetLog(req.TrackingID) if isDuplicate || req.TrackingID == "" { req.TrackingID = uuid.NewString() } ``` **Filename construction — `service/internal/executor/executor.go` (line 1042):** The tracking ID is interpolated directly into the log filename: ```go filename := fmt.Sprintf("%v.%v.%v", req.logEntry.ActionTitle, req.logEntry.DatetimeStarted.Unix(), req.logEntry.ExecutionTrackingID, ) ``` **File write — `service/internal/executor/executor.go` (lines 1068–1069 and 1082–1083):** The filename is joined to the configured log directory using `path.Join`, which calls `path.Clean` internally. `path.Clean` resolves `..` path segments, causing the final file path to escape the intended directory: ```go // Results file (.yaml) filepath := path.Join(dir, filename+".yaml") err = os.WriteFile(filepath, data, 0600) // Output file (.log) filepath := path.Join(dir, filename+".log") err := os.WriteFile(filepath, []byte(data), 0600) ``` ### Proof of Concept An attacker sends the following `StartAction` request (Connect RPC or REST): ```json { "bindingId": "<any-executable-action-id>", "uniqueTrackingId": "../../../tmp/pwned" } ``` Assuming the action title is `Ping the Internet` and the timestamp is `1741320000`, the constructed filename becomes: ``` Ping the Internet.1741320000.../../../tmp/pwned ``` When `path.Join` processes this with a configured results directory like `/var/olivetin/logs`: ``` path.Join("/var/olivetin/logs", "Ping the Internet.1741320000.../../../tmp/pwned.yaml") ``` `path.Clean` resolves the traversal: 1. Path segments: `["var", "olivetin", "logs", "Ping the Internet.1741320000...", "..", "..", "..", "tmp", "pwned.yaml"]` 2. The `..` segments traverse upward past the log directory. 3. Final resolved path: `/tmp/pwned.yaml` Two files are written: - **`.yaml` file** — contains YAML-serialized `InternalLogEntry` (action title, icon, timestamps, exit code, output, tags, username, tracking ID) - **`.log` file** — contains the raw command output (potentially attacker-influenced if the action echoes its arguments) ### Impact - **Arbitrary file write** to any path writable by the OliveTin process. - OliveTin frequently runs as root inside Docker containers, so the writable scope is often the entire filesystem. - An attacker could: - Overwrite OliveTin's own `sessions.yaml` to inject authenticated sessions. - Write to entity file directories to inject malicious entity data. - Write to system cron directories or other locations to achieve remote code execution. - Cause denial of service by overwriting critical system files. ### Suggested Fix Validate the `UniqueTrackingId` to ensure it only contains safe characters before use. A strict UUID format check is the simplest approach: ```go import "regexp" var validTrackingID = regexp.MustCompile(`^[a-fA-F0-9\-]+$`) // In ExecRequest, before accepting the user-supplied ID: if req.TrackingID == "" || !validTrackingID.MatchString(req.TrackingID) { req.TrackingID = uuid.NewString() } ``` Alternatively, sanitize the filename in `stepSaveLog` by stripping or rejecting path separators and `..` sequences.

CVE-2026-31817 Affected Github.com/OliveTin/OliveTin Versions

1 component(s)
Fixed Versions:
0.0.0-20260309102040-b03af0e2eca3
Product / Package Ecosystem Affected Versions Fixed Version
github.com/OliveTin/OliveTin
Go
< 0.0.0-20260309102040-b03af0e2eca3
0.0.0-20260309102040-b03af0e2eca3

References

Frequently Asked Questions

What is CVE-2026-31817?
CVE-2026-31817 is a security vulnerability in Github.com/OliveTin/OliveTin involving OliveTin's unsafe parsing of UniqueTrackingId can be used to write files under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
Which Github.com/OliveTin/OliveTin versions are affected?
Affected versions include releases prior to 0.0.0-20260309102040-b03af0e2eca3 across affected packages: github.com/OliveTin/OliveTin.
What version fixes CVE-2026-31817?
Upgrading to 0.0.0-20260309102040-b03af0e2eca3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/OliveTin/OliveTin affected?
Yes, github.com/OliveTin/OliveTin is affected in releases prior to 0.0.0-20260309102040-b03af0e2eca3. Upgrade your dependency to 0.0.0-20260309102040-b03af0e2eca3 or later.
What is the CVSS score of CVE-2026-31817?
CVE-2026-31817 has a CVSS v3.1 base score of 8.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L.
What CWE is associated with CVE-2026-31817?
CVE-2026-31817 is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.).
How can I check Go dependencies for CVE-2026-31817?
Run the dependency tree command: 'inspect dependencies for github.com/OliveTin/OliveTin'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-364q-w7vh-vhpc",
  "modified" : "2026-03-11T05:46:08Z",
  "published" : "2026-03-11T00:09:41Z",
  "aliases" : [ "CVE-2026-31817" ],
  "summary" : "OliveTin's unsafe parsing of UniqueTrackingId can be used to write files",
  "details" : "When the `saveLogs` feature is enabled, OliveTin persists execution log entries to disk. The filename used for these log files is constructed in part from the user-supplied `UniqueTrackingId` field in the `StartAction` API request. This value is not validated or sanitized before being used in a file path, allowing an attacker to use directory traversal sequences (e.g., `../../../`) to write files to arbitrary locations on the filesystem.\n### Affected Code\n\n**Entry point — `service/internal/api/api.go` (line 130):**\n\nThe `UniqueTrackingId` from the API request is passed directly to the executor without validation:\n\n```go\nexecReq := executor.ExecutionRequest{\n    Binding:    pair,\n    TrackingID: req.Msg.UniqueTrackingId, // user-controlled, no validation\n    // ...\n}\n```\n\n**Tracking ID accepted as-is — `service/internal/executor/executor.go` (lines 508–512):**\n\nThe tracking ID is only replaced with a UUID if it is empty or a duplicate. Any other string, including one containing path separators, is accepted:\n\n```go\n_, isDuplicate := e.GetLog(req.TrackingID)\n\nif isDuplicate || req.TrackingID == \"\" {\n    req.TrackingID = uuid.NewString()\n}\n```\n\n**Filename construction — `service/internal/executor/executor.go` (line 1042):**\n\nThe tracking ID is interpolated directly into the log filename:\n\n```go\nfilename := fmt.Sprintf(\"%v.%v.%v\",\n    req.logEntry.ActionTitle,\n    req.logEntry.DatetimeStarted.Unix(),\n    req.logEntry.ExecutionTrackingID,\n)\n```\n\n**File write — `service/internal/executor/executor.go` (lines 1068–1069 and 1082–1083):**\n\nThe filename is joined to the configured log directory using `path.Join`, which calls `path.Clean` internally. `path.Clean` resolves `..` path segments, causing the final file path to escape the intended directory:\n\n```go\n// Results file (.yaml)\nfilepath := path.Join(dir, filename+\".yaml\")\nerr = os.WriteFile(filepath, data, 0600)\n\n// Output file (.log)\nfilepath := path.Join(dir, filename+\".log\")\nerr := os.WriteFile(filepath, []byte(data), 0600)\n```\n\n### Proof of Concept\n\nAn attacker sends the following `StartAction` request (Connect RPC or REST):\n\n```json\n{\n  \"bindingId\": \"<any-executable-action-id>\",\n  \"uniqueTrackingId\": \"../../../tmp/pwned\"\n}\n```\n\nAssuming the action title is `Ping the Internet` and the timestamp is `1741320000`, the constructed filename becomes:\n\n```\nPing the Internet.1741320000.../../../tmp/pwned\n```\n\nWhen `path.Join` processes this with a configured results directory like `/var/olivetin/logs`:\n\n```\npath.Join(\"/var/olivetin/logs\", \"Ping the Internet.1741320000.../../../tmp/pwned.yaml\")\n```\n\n`path.Clean` resolves the traversal:\n\n1. Path segments: `[\"var\", \"olivetin\", \"logs\", \"Ping the Internet.1741320000...\", \"..\", \"..\", \"..\", \"tmp\", \"pwned.yaml\"]`\n2. The `..` segments traverse upward past the log directory.\n3. Final resolved path: `/tmp/pwned.yaml`\n\nTwo files are written:\n\n- **`.yaml` file** — contains YAML-serialized `InternalLogEntry` (action title, icon, timestamps, exit code, output, tags, username, tracking ID)\n- **`.log` file** — contains the raw command output (potentially attacker-influenced if the action echoes its arguments)\n\n### Impact\n\n- **Arbitrary file write** to any path writable by the OliveTin process.\n- OliveTin frequently runs as root inside Docker containers, so the writable scope is often the entire filesystem.\n- An attacker could:\n  - Overwrite OliveTin's own `sessions.yaml` to inject authenticated sessions.\n  - Write to entity file directories to inject malicious entity data.\n  - Write to system cron directories or other locations to achieve remote code execution.\n  - Cause denial of service by overwriting critical system files.\n\n### Suggested Fix\n\nValidate the `UniqueTrackingId` to ensure it only contains safe characters before use. A strict UUID format check is the simplest approach:\n\n```go\nimport \"regexp\"\n\nvar validTrackingID = regexp.MustCompile(`^[a-fA-F0-9\\-]+$`)\n\n// In ExecRequest, before accepting the user-supplied ID:\nif req.TrackingID == \"\" || !validTrackingID.MatchString(req.TrackingID) {\n    req.TrackingID = uuid.NewString()\n}\n```\n\nAlternatively, sanitize the filename in `stepSaveLog` by stripping or rejecting path separators and `..` sequences.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/OliveTin/OliveTin"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.0.0-20260309102040-b03af0e2eca3"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/security/advisories/GHSA-364q-w7vh-vhpc"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-31817"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/commit/2f77000de44f65690f257e3cf8e2c8462b0e74c7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/OliveTin/OliveTin"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/releases/tag/3000.11.2"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-11T00:09:41Z",
    "nvd_published_at" : "2026-03-10T22:16:19Z"
  }
}