CVE-2026-67439: OliveTin StartActionAndWait Endpoints Bypass `logs` Permission Vulnerability

MODERATE
Advisory Identifier: GHSA-jm28-2wcr-qf3h
CVSS 4.3
CWE-863
Published
Advisory Summary

CVE-2026-67439 is a MODERATE (CVSS 4.3) startactionandwait endpoints bypass `logs` permission vulnerability (CWE-863: Incorrect Authorization) affecting OliveTin libraries in the Go ecosystem. The issue involves startactionandwait endpoints bypass `logs` permission and return action output. Remediation is available by upgrading affected packages to version 0.0.0-20260708085316-e421780c9885.

CVE-2026-67439 at a Glance

CVE Identifier CVE-2026-67439
GHSA Identifier GHSA-jm28-2wcr-qf3h
Severity MODERATE
CVSS v3.1 Base Score 4.3
CWE Classification CWE-863: Incorrect Authorization
Affected Product OliveTin
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 4.3

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:U/C:L/I:N/A:N).

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

How to Fix CVE-2026-67439

To remediate this vulnerability, upgrade all affected 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-20260708085316-e421780c9885
Upgrade github.com/OliveTin/OliveTin to 0.0.0-20260708085316-e421780c9885
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-67439, inspect your project dependencies for OliveTin:

inspect dependencies for github.com/OliveTin/OliveTin

Analyze the terminal output to locate any version of 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-20260708085316-e421780c9885), 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-863: Incorrect Authorization, where the product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. In 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

## Summary The synchronous execution RPCs `StartActionAndWait` and `StartActionByGetAndWait` return the full `LogEntry` for the just-executed action without checking whether the caller is allowed to read that action's logs. OliveTin's ACL model separates `exec` from `logs`. A deployment can intentionally allow a user to run an action while denying access to its historical or live output. That separation is enforced in `GetLogs`, `GetActionLogs`, `ExecutionStatus`, and `EventStream`, but it is not enforced in the synchronous `...AndWait` endpoints. As a result, any user who can execute an action through these endpoints can read the action output immediately even when the action's ACL explicitly sets `logs:false`. ## Details OliveTin defines separate per-action permissions: ```go // service/internal/config/config.go type PermissionsList struct { View bool `koanf:"view"` Exec bool `koanf:"exec"` Logs bool `koanf:"logs"` Kill bool `koanf:"kill"` } ``` The normal log and streaming paths correctly enforce `logs` permission: ```go // service/internal/api/api.go func (api *oliveTinAPI) isLogEntryAllowed(e *executor.InternalLogEntry, user *authpublic.AuthenticatedUser) bool { if user == nil || !isValidLogEntry(e) { return false } return acl.IsAllowedLogs(api.cfg, user, e.Binding.Action) } ``` That check is used by: - `GetLogs` - `GetActionLogs` - `ExecutionStatus` - `EventStream` However, the synchronous execution endpoints directly return the created `LogEntry` without any `logs` ACL check: ```go // service/internal/api/api.go func (api *oliveTinAPI) StartActionAndWait(ctx ctx.Context, req *connect.Request[apiv1.StartActionAndWaitRequest]) (*connect.Response[apiv1.StartActionAndWaitResponse], error) { ... internalLogEntry, ok := api.startActionAndWaitRun(binding, args, user) if !ok { return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("execution not found")) } return connect.NewResponse(&apiv1.StartActionAndWaitResponse{ LogEntry: api.internalLogEntryToPb(internalLogEntry, user), }), nil } func (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *connect.Request[apiv1.StartActionByGetAndWaitRequest]) (*connect.Response[apiv1.StartActionByGetAndWaitResponse], error) { ... internalLogEntry, ok := api.executor.GetLog(execReq.TrackingID) if ok { return connect.NewResponse(&apiv1.StartActionByGetAndWaitResponse{ LogEntry: api.internalLogEntryToPb(internalLogEntry, user), }), nil } return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("execution not found")) } ``` And `internalLogEntryToPb()` includes the full output: ```go // service/internal/api/api.go func (api *oliveTinAPI) internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *authpublic.AuthenticatedUser) *apiv1.LogEntry { pble := &apiv1.LogEntry{ ActionTitle: logEntry.ActionTitle, Output: logEntry.Output, ExitCode: logEntry.ExitCode, ExecutionTrackingId: logEntry.ExecutionTrackingID, ... } ... return pble } ``` The executor separately enforces `exec` permission, but there is no subsequent check that the response should omit or deny `Output` when `logs:false`. ## Local Reproduction I verified this locally with a one-off test against the real `StartActionAndWait` handler. Configuration used: - action `secret_action` with shell `echo SECRET_FROM_ACTION` - user `low` matched by ACL: - `exec: true` - `logs: false` - `view: false` - `kill: false` Then I invoked `StartActionAndWait` as `low` through the real handler path using header-based auth. Observed output from the test run: ```text === RUN TestTempStartActionAndWaitLeaksOutputWithoutLogsPermission time="2026-03-12T23:36:33+01:00" level=info msg="Action requested" actionTitle=secret-action tags="[]" time="2026-03-12T23:36:33+01:00" level=info msg="Action parse args - Before" actionTitle=secret-action cmd="echo SECRET_FROM_ACTION" time="2026-03-12T23:36:33+01:00" level=info msg="Action parse args - After" actionTitle=secret-action cmd="echo SECRET_FROM_ACTION" time="2026-03-12T23:36:33+01:00" level=info msg="Action started" actionTitle=secret-action timeout=5 time="2026-03-12T23:36:33+01:00" level=info msg="Action finished" actionTitle=secret-action exit=0 outputLength=40 timedOut=false temp_acl_bypass_test.go:56: output="S\x00E\x00C\x00R\x00E\x00T\x00_\x00F\x00R\x00O\x00M\x00_\x00A\x00C\x00T\x00I\x00O\x00N\x00\r\x00\n\x00" blocked=false action="secret-action" --- PASS: TestTempStartActionAndWaitLeaksOutputWithoutLogsPermission (0.03s) ``` The UTF-16LE formatting is from Windows `echo`, but the key result is that the response returned the real command output even though the caller's ACL explicitly denied log access. ## Impact - **Bypass of log confidentiality controls:** Operators may configure actions to be executable but not log-readable. The `...AndWait` endpoints break that separation. - **Disclosure of secrets printed by actions:** Many OliveTin actions wrap administrative scripts and commands whose stdout/stderr may contain credentials, internal paths, hostnames, tokens, or sensitive operational data. - **Adjacent to previous output-leak bugs:** OliveTin already had an EventStream output disclosure bug. This is a separate response-path authorization gap on the synchronous execution APIs. ## Recommended Fix Enforce `logs` permission before returning `LogEntry` content from synchronous execution endpoints. Two reasonable fixes: 1. Deny the endpoint response when `logs:false` ```go if !acl.IsAllowedLogs(api.cfg, user, binding.Action) { return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf("permission denied to view action output")) } ``` 2. Or redact log-bearing fields when `logs:false` ```go pb := api.internalLogEntryToPb(internalLogEntry, user) if !acl.IsAllowedLogs(api.cfg, user, binding.Action) { pb.Output = "" pb.ExitCode = 0 } return connect.NewResponse(&apiv1.StartActionAndWaitResponse{LogEntry: pb}), nil ``` The same fix should be applied to both: - `StartActionAndWait` - `StartActionByGetAndWait` ## References - `service/internal/api/api.go` - `service/internal/config/config.go` - `service/internal/acl/acl.go`

CVE-2026-67439 Affected OliveTin Versions

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

References

Frequently Asked Questions

What is CVE-2026-67439?
CVE-2026-67439 is a security vulnerability in OliveTin involving StartActionAndWait Endpoints Bypass `logs` Permission and Return Action Output under CWE-863: Incorrect Authorization.
Which OliveTin versions are affected?
Affected versions include releases prior to 0.0.0-20260708085316-e421780c9885 across affected packages: github.com/OliveTin/OliveTin.
What version fixes CVE-2026-67439?
Upgrading to 0.0.0-20260708085316-e421780c9885 (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-20260708085316-e421780c9885. Upgrade your dependency to 0.0.0-20260708085316-e421780c9885 or later.
What is the CVSS score of CVE-2026-67439?
CVE-2026-67439 has a CVSS v3.1 base score of 4.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N.
What CWE is associated with CVE-2026-67439?
CVE-2026-67439 is classified under CWE-863: Incorrect Authorization (The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.).
How can I check Go dependencies for CVE-2026-67439?
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-jm28-2wcr-qf3h",
  "modified" : "2026-07-30T14:25:20Z",
  "published" : "2026-07-30T14:25:20Z",
  "aliases" : [ "CVE-2026-67439" ],
  "summary" : "OliveTin: StartActionAndWait Endpoints Bypass `logs` Permission and Return Action Output",
  "details" : "## Summary\n\nThe synchronous execution RPCs `StartActionAndWait` and `StartActionByGetAndWait` return the full `LogEntry` for the just-executed action without checking whether the caller is allowed to read that action's logs.\n\nOliveTin's ACL model separates `exec` from `logs`. A deployment can intentionally allow a user to run an action while denying access to its historical or live output. That separation is enforced in `GetLogs`, `GetActionLogs`, `ExecutionStatus`, and `EventStream`, but it is not enforced in the synchronous `...AndWait` endpoints.\n\nAs a result, any user who can execute an action through these endpoints can read the action output immediately even when the action's ACL explicitly sets `logs:false`.\n\n## Details\n\nOliveTin defines separate per-action permissions:\n\n```go\n// service/internal/config/config.go\ntype PermissionsList struct {\n    View bool `koanf:\"view\"`\n    Exec bool `koanf:\"exec\"`\n    Logs bool `koanf:\"logs\"`\n    Kill bool `koanf:\"kill\"`\n}\n```\n\nThe normal log and streaming paths correctly enforce `logs` permission:\n\n```go\n// service/internal/api/api.go\nfunc (api *oliveTinAPI) isLogEntryAllowed(e *executor.InternalLogEntry, user *authpublic.AuthenticatedUser) bool {\n    if user == nil || !isValidLogEntry(e) {\n        return false\n    }\n    return acl.IsAllowedLogs(api.cfg, user, e.Binding.Action)\n}\n```\n\nThat check is used by:\n\n- `GetLogs`\n- `GetActionLogs`\n- `ExecutionStatus`\n- `EventStream`\n\nHowever, the synchronous execution endpoints directly return the created `LogEntry` without any `logs` ACL check:\n\n```go\n// service/internal/api/api.go\nfunc (api *oliveTinAPI) StartActionAndWait(ctx ctx.Context, req *connect.Request[apiv1.StartActionAndWaitRequest]) (*connect.Response[apiv1.StartActionAndWaitResponse], error) {\n    ...\n    internalLogEntry, ok := api.startActionAndWaitRun(binding, args, user)\n    if !ok {\n        return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf(\"execution not found\"))\n    }\n    return connect.NewResponse(&apiv1.StartActionAndWaitResponse{\n        LogEntry: api.internalLogEntryToPb(internalLogEntry, user),\n    }), nil\n}\n\nfunc (api *oliveTinAPI) StartActionByGetAndWait(ctx ctx.Context, req *connect.Request[apiv1.StartActionByGetAndWaitRequest]) (*connect.Response[apiv1.StartActionByGetAndWaitResponse], error) {\n    ...\n    internalLogEntry, ok := api.executor.GetLog(execReq.TrackingID)\n    if ok {\n        return connect.NewResponse(&apiv1.StartActionByGetAndWaitResponse{\n            LogEntry: api.internalLogEntryToPb(internalLogEntry, user),\n        }), nil\n    }\n    return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf(\"execution not found\"))\n}\n```\n\nAnd `internalLogEntryToPb()` includes the full output:\n\n```go\n// service/internal/api/api.go\nfunc (api *oliveTinAPI) internalLogEntryToPb(logEntry *executor.InternalLogEntry, authenticatedUser *authpublic.AuthenticatedUser) *apiv1.LogEntry {\n    pble := &apiv1.LogEntry{\n        ActionTitle:         logEntry.ActionTitle,\n        Output:              logEntry.Output,\n        ExitCode:            logEntry.ExitCode,\n        ExecutionTrackingId: logEntry.ExecutionTrackingID,\n        ...\n    }\n    ...\n    return pble\n}\n```\n\nThe executor separately enforces `exec` permission, but there is no subsequent check that the response should omit or deny `Output` when `logs:false`.\n\n## Local Reproduction\n\nI verified this locally with a one-off test against the real `StartActionAndWait` handler.\n\nConfiguration used:\n\n- action `secret_action` with shell `echo SECRET_FROM_ACTION`\n- user `low` matched by ACL:\n  - `exec: true`\n  - `logs: false`\n  - `view: false`\n  - `kill: false`\n\nThen I invoked `StartActionAndWait` as `low` through the real handler path using header-based auth.\n\nObserved output from the test run:\n\n```text\n=== RUN   TestTempStartActionAndWaitLeaksOutputWithoutLogsPermission\ntime=\"2026-03-12T23:36:33+01:00\" level=info msg=\"Action requested\" actionTitle=secret-action tags=\"[]\"\ntime=\"2026-03-12T23:36:33+01:00\" level=info msg=\"Action parse args - Before\" actionTitle=secret-action cmd=\"echo SECRET_FROM_ACTION\"\ntime=\"2026-03-12T23:36:33+01:00\" level=info msg=\"Action parse args - After\" actionTitle=secret-action cmd=\"echo SECRET_FROM_ACTION\"\ntime=\"2026-03-12T23:36:33+01:00\" level=info msg=\"Action started\" actionTitle=secret-action timeout=5\ntime=\"2026-03-12T23:36:33+01:00\" level=info msg=\"Action finished\" actionTitle=secret-action exit=0 outputLength=40 timedOut=false\n    temp_acl_bypass_test.go:56: output=\"S\\x00E\\x00C\\x00R\\x00E\\x00T\\x00_\\x00F\\x00R\\x00O\\x00M\\x00_\\x00A\\x00C\\x00T\\x00I\\x00O\\x00N\\x00\\r\\x00\\n\\x00\" blocked=false action=\"secret-action\"\n--- PASS: TestTempStartActionAndWaitLeaksOutputWithoutLogsPermission (0.03s)\n```\n\nThe UTF-16LE formatting is from Windows `echo`, but the key result is that the response returned the real command output even though the caller's ACL explicitly denied log access.\n\n## Impact\n\n- **Bypass of log confidentiality controls:** Operators may configure actions to be executable but not log-readable. The `...AndWait` endpoints break that separation.\n- **Disclosure of secrets printed by actions:** Many OliveTin actions wrap administrative scripts and commands whose stdout/stderr may contain credentials, internal paths, hostnames, tokens, or sensitive operational data.\n- **Adjacent to previous output-leak bugs:** OliveTin already had an EventStream output disclosure bug. This is a separate response-path authorization gap on the synchronous execution APIs.\n\n## Recommended Fix\n\nEnforce `logs` permission before returning `LogEntry` content from synchronous execution endpoints.\n\nTwo reasonable fixes:\n\n1. Deny the endpoint response when `logs:false`\n\n```go\nif !acl.IsAllowedLogs(api.cfg, user, binding.Action) {\n    return nil, connect.NewError(connect.CodePermissionDenied, fmt.Errorf(\"permission denied to view action output\"))\n}\n```\n\n2. Or redact log-bearing fields when `logs:false`\n\n```go\npb := api.internalLogEntryToPb(internalLogEntry, user)\nif !acl.IsAllowedLogs(api.cfg, user, binding.Action) {\n    pb.Output = \"\"\n    pb.ExitCode = 0\n}\nreturn connect.NewResponse(&apiv1.StartActionAndWaitResponse{LogEntry: pb}), nil\n```\n\nThe same fix should be applied to both:\n\n- `StartActionAndWait`\n- `StartActionByGetAndWait`\n\n## References\n\n- `service/internal/api/api.go`\n- `service/internal/config/config.go`\n- `service/internal/acl/acl.go`",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/OliveTin/OliveTin"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.0.0-20260708085316-e421780c9885"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/security/advisories/GHSA-jm28-2wcr-qf3h"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-67439"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/commit/e421780c9885aa5024d2f47b4ed4898f2f18eb90"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/OliveTin/OliveTin"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/OliveTin/OliveTin/releases/tag/3000.17.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-863" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-30T14:25:20Z",
    "nvd_published_at" : "2026-07-29T21:17:48Z"
  }
}