GHSA-f637-w7p2-m7fx CVE-2026-48709 GO-2026-5347
OliveTin: ValidateArgumentType API Endpoint's Missing Authentication Allows Action and Argument Enumeration
- Severity
- 3.7 / 10
- Low · CVSS 3.1
- Exploit chance (EPSS)
- 0.33%
- Chance of exploitation in the next 30 days. Higher than 26.03% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-862 Missing Authorization
- Fix
0.0.0-20260521230847-a3865704c854- Upgrade github.com/OliveTin/OliveTin to this version or later
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
CodeNotFounderror -
Invalid binding: Returns
CodeNotFounderror
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: trueconfigured
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
-
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.
-
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. -
Limited Scope: This is only exploitable when
AuthRequireGuestsToLogin: trueis 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
}
Affected versions
Go
| Package | Vulnerable | Fixed in |
|---|---|---|
| github.com/OliveTin/OliveTin | < 0.0.0-20260521230847-a3865704c854 |
0.0.0-20260521230847-a3865704c854 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
github.com/OliveTin/OliveTin Go → 0.0.0-20260521230847-a3865704c854
- go
go get github.com/OliveTin/OliveTin@v0.0.0-20260521230847-a3865704c854 && go mod tidy
Severity breakdown
CVSS 3.1 3.7
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
- Attack vector
- Network
- Attack complexity
- High
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- Low
- Integrity
- None
- Availability
- None
Weakness
CWE-862: Missing Authorization
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
How to prevent it
- Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
- Architecture and Design: Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
- Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
- Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
- System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-jm28-2wcr-qf3h OliveTin: StartActionAndWait Endpoints Bypass `logs` Permission and Return Action Output | Medium | Also affects github.com/OliveTin/OliveTin |
| GHSA-xc5w-4v5w-7x65 OliveTin OS Command Injection via Custom regex: Argument Type Bypassing Shell Safety Check | Medium | Also affects github.com/OliveTin/OliveTin |
| GHSA-xpxj-f2fm-rqch OliveTin: Unauthenticated DoS via OAuth2 State Memory Exhaustion (Unbounded Map Growth) | High | Also affects github.com/OliveTin/OliveTin |
| GHSA-prj9-97mp-mwh2 OliveTin has Unvalidated `ot_`-prefixed Arguments that Bypass Input Filtering | Medium | Also affects github.com/OliveTin/OliveTin |
| GHSA-7fq5-7wr8-rjwj OliveTin has a Concurrent Template Parsing Race Condition which Leads to Cross-Request Command Contamination | High | Also affects github.com/OliveTin/OliveTin |
| GHSA-xx6g-43w2-9g6g OliveTin's email argument makes compliance harder, enables log injection | Medium | Also affects github.com/OliveTin/OliveTin |
| GHSA-228v-wc5r-j8m7 OliveTin Vulnerable to Unauthorized Action Output Disclosure via EventStream | Medium | Also affects github.com/OliveTin/OliveTin |
| GHSA-364q-w7vh-vhpc OliveTin's unsafe parsing of UniqueTrackingId can be used to write files | High | Also affects github.com/OliveTin/OliveTin |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor