Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ window.addEventListener('message', (e) => {
});
```

**targetOrigin bypass via IP normalization:** When `postMessage(data, targetOrigin)` uses regex validation like `/https?:\/\/[^.]+[.]target[.]com/`, the `[^.]+` class matches `/` -- so `http://2130706433/.target.com` passes the regex. The browser's URL parser then normalizes the integer IP to `127.0.0.1` and sends the message to `http://127.0.0.1` (attacker-controlled). Same technique works with hex (`0x7f000001`) and octal IP forms. Check: does the sender validate `targetOrigin` with regex rather than strict string equality? If yes, test integer IP + path injection.

**Checkpoint:** For each handler, verify: (1) strict `e.origin` equality check exists, (2) no `window.origin` comparison, (3) no `startsWith`/`endsWith` on origin, (4) data is not passed to dynamic execution (`window[data.func]`).

### 5. Test CSTI (Client-Side Template Injection)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
name: git-integration-exploitation
description: Exploit git integrations in SaaS and cloud services -- argument injection per git subcommand, JGit vs native git attack path selection, .git/config append-only takeover, error-based file read via --pathspec-from-file, and symlink-based filesystem escape. Use when target has git-backed features like web IDEs, CI/CD pipelines, deployment from repo, LookML/Dataform-style config, or any feature that clones/pulls/commits on the server side.
---

# Git Integration Exploitation

Systematic audit methodology for SaaS services that integrate git server-side. The attack surface is not git itself -- it is the service's assumptions about what git operations are safe.

## When to Use

- Target has a web IDE, notebook, or config editor backed by git
- CI/CD pipeline clones user-controlled repos
- Deployment feature pulls from git (Heroku-style, Cloud Build, Dataform)
- Service accepts git URLs as input (import, migration, dependency resolution)
- `.git/` directory or git CLI invocation visible in errors, headers, or source

## Recon: Identify the Git Implementation

The first decision point. Different implementations have different exploitable surfaces.

| Implementation | Hooks | fsmonitor | symlinks | Argument injection |
|---|---|---|---|---|
| **Native git CLI** | Yes | Yes | Yes (Linux/macOS default) | Yes |
| **JGit (Java)** | No | No | Only if `core.symlinks=true` in config | No (API-based) |
| **libgit2 / go-git** | No | No | Varies | No (API-based) |

**How to fingerprint:**
- Error messages: Java stack traces (JGit), C/Go traces (libgit2/go-git), shell errors (native)
- Timing: native git shells out (slower cold start), JGit is in-process
- Behavior: create a repo with a `post-checkout` hook -- if it fires, native git

**Rule:** If JGit, skip hooks/fsmonitor -- pivot to symlinks or config-based file read/write. If native git, hooks and fsmonitor are the fastest path to RCE.

## Attack Primitives

### 1. Argument Injection (native git only)

The service constructs a git CLI command with user-controlled input (branch name, file path, remote URL). If the input starts with `-`, git interprets it as an option.

**The surface is per-command** -- enumerate which git subcommand the service calls, then check that command's dangerous flags:

| Git command | Dangerous flag | Effect |
|---|---|---|
| `git clone` / `git fetch` | `--upload-pack=<cmd>` | Arbitrary command execution |
| `git rm` | `--pathspec-from-file=<path>` | Read arbitrary file (contents leak via error) |
| `git diff` | `--output=<path>` | Write diff output to arbitrary path |
| `git log` | `--output=<path>` | Write log output to arbitrary path |
| `git apply` | `--directory=<path>` | Control patch application target directory |
| `git push` | `--receive-pack=<cmd>` | Arbitrary command execution on remote |

**Error-based file read via `--pathspec-from-file`:** Create a file or folder named `--pathspec-from-file=/etc/passwd`. When the service runs `git rm` on it, git reads the target file, tries to parse each line as a pathspec, and dumps non-matching lines in error output. Works best on text files with non-path characters. Binary files or files with path-like content may not leak meaningfully. Test with `/etc/hostname` (short, predictable) before targeting larger files.

### 2. Config Append-Only Takeover

Git's `.git/config` uses INI format where duplicate `[core]` sections are merged -- last value wins (see `config-file-parsing-bugs` skill for the general INI parser pattern). Append-only write access to `.git/config` lets you override any config key, including `core.fsmonitor` (RCE on next `git status`) and `core.symlinks` (enable symlink following on JGit).

**Where to look:** Any API that writes to the repo working directory without path sanitization (`WriteFile`, file upload, template generation). Test: write to `.git/config` directly -- many services forget to block the `.git/` prefix.

### 3. Symlink Filesystem Escape

When `core.symlinks = true` (default on Linux/macOS for native git), git creates real filesystem symlinks during checkout. A repo containing a symlink to `/` exposes the entire filesystem through the service's file browser. For symlink attacks via archive upload (non-git), see `archive-path-traversal` skill.

**JGit twist:** JGit defaults `core.symlinks = false`. But if you can write to `.git/config` (primitive #2), add `symlinks = true` under `[core]`. Next checkout (triggered by pull, merge, or reset) creates real symlinks.

**Cross-tenant escalation:** In multi-tenant cloud services, filesystem escape via symlink often reaches other tenants' repo directories on shared infrastructure.

### 4. Embedded Bare Repository

Push a repo containing a subdirectory structured as a bare git repo (has `HEAD`, `config`, `objects/`, `refs/`). If the service runs any git command from within that subdirectory, git discovers the embedded config.

Weaponize: set `bare = false` + `core.worktree = .` + `core.fsmonitor = <cmd>` in the embedded config. Any `git status` from that directory triggers execution.

### 5. TOCTOU on Config Regeneration

Services that regenerate `.git/config` before each git operation (as a safety measure) create a race window. Concurrent requests -- one writing the malicious config, one triggering the git operation -- can win the race.

**Test:** Use an intruder/fuzzer with two request groups running in parallel. Usually wins within 5-20 attempts.

## Audit Checklist

```
1. [ ] Does the service expose git-backed features? (IDE, deploy, import, CI)
2. [ ] Which git implementation? (native / JGit / libgit2 / go-git)
3. [ ] Can you write to .git/config? (file API, upload, template injection)
4. [ ] Which git subcommands does the service call? (trigger commit/push/pull/diff,
grep responses for subcommand names, review client JS for action/command params)
5. [ ] Is user input used in git CLI arguments? (branch, path, remote URL, ref name)
6. [ ] Does the file browser follow symlinks? (create symlink in repo, check UI)
7. [ ] Does the service regenerate config before operations? (race condition window)
8. [ ] Multi-tenant? (filesystem escape = cross-tenant = critical)
```

## References

- [CVE-2024-32002](https://nvd.nist.gov/vuln/detail/CVE-2024-32002) -- Git recursive clone RCE via embedded bare repo + symlink
- [CVE-2022-39253](https://nvd.nist.gov/vuln/detail/CVE-2022-39253) -- Git local clone file disclosure via symlink
- [GCP-2025-045](https://cloud.google.com/dataform/docs/security-bulletins) -- Google Dataform cross-tenant via symlink (CVSS 10.0)
- [Tenable: LookOut](https://www.tenable.com/blog/google-looker-vulnerabilities-rce-internal-access-lookout) -- Google Looker RCE via hook override + race condition
152 changes: 152 additions & 0 deletions capabilities/web-security/skills/http-query-method/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
name: http-query-method
description: Exploit HTTP QUERY method (RFC 10008, June 2026) parser differentials -- WAF body inspection bypass, cache poisoning via body-ignorant caching, and request smuggling from body handling disagreements. Use when target has a CDN/cache/WAF layer and accepts or forwards unknown HTTP methods, or when testing for method-based parser differentials.
---

# HTTP QUERY Method Exploitation

RFC 10008 (June 2026) defines QUERY -- the first new HTTP method standardized in 20+ years. It is semantically GET-with-a-body: safe, idempotent, cacheable, but the response cache key MUST include the request body and Content-Type.

Most infrastructure does not implement this correctly yet. The adoption gap between spec and deployment is the attack surface.

## When to Use

- Target sits behind a CDN, cache, or WAF (most do)
- WAF blocks injection payloads in POST bodies but you haven't tested QUERY
- Cache layer detected (Varnish, Squid, CloudFront, Fastly, Cloudflare, Akamai)
- Target accepts or forwards unrecognized HTTP methods (test with `curl -X QUERY`)
- You've exhausted standard `parser-differential-bypass` and `h2-waf-bypass` techniques

## QUERY vs GET vs POST

| Property | GET | POST | QUERY |
|---|---|---|---|
| Safe / idempotent | Yes / Yes | No / No | Yes / Yes |
| Body | Ignored by most infra | Required | Required |
| Cacheable | Yes (URL-keyed) | No | Yes (URL + body + Content-Type keyed) |
| CORS safelisted | Yes | Yes (simple) | No (triggers preflight) |

The critical difference: QUERY responses are cacheable but the cache key must include the body. Caches that don't understand QUERY will key on URL only -- identical to GET -- creating poisoning conditions.

## Attack Scenarios

### 1. WAF Body Inspection Bypass

WAFs apply method-specific inspection. Most inspect POST bodies for injection. If the WAF doesn't recognize QUERY, it may skip body inspection entirely or apply GET-tier rules (URL only).

```bash
# Baseline: POST blocked by WAF
curl -X POST https://target.com/api/search \
-d "q=' OR 1=1--"

# Test: same payload via QUERY
curl -X QUERY https://target.com/api/search \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "q=' OR 1=1--"
```

If POST returns WAF block (403/406) but QUERY reaches the backend, you have an inspection gap. The QUERY method is the bypass -- the finding is whatever the payload achieves (SQLi, XSS, etc.).

### 2. Cache Poisoning via Body-Ignorant Caching

If the cache treats QUERY like GET (keys on URL only, ignores body):

**Primary case (QUERY-to-QUERY, body ignored in cache key):**

1. Attacker sends `QUERY /search` with body `{"q":"<script>alert(1)</script>"}`
2. Backend processes the query, returns results containing the reflected payload
3. Cache stores response keyed on method + URL only (body ignored)
4. Victim sends `QUERY /search` with a different body -- receives the attacker's cached response

**Escalated case (method also ignored in cache key):**

If the cache ignores both body and method, the poisoned QUERY response is also served to `GET /search` requests -- affecting all users, not just QUERY senders.

```bash
# Step 1: poison the cache
curl -X QUERY https://target.com/search \
-H "Content-Type: application/json" \
-d '{"q":"<script>alert(document.domain)</script>"}'

# Step 2: verify cache serves poisoned response to clean request
curl https://target.com/search
```

Check `Age`, `X-Cache`, `CF-Cache-Status` headers to confirm caching behavior.

### 3. Request Smuggling via Body Handling Disagreement

Front-end (CDN/LB) treats QUERY as bodyless (like GET), ignores Content-Length. Back-end reads the body. The "ignored" body becomes a new request from the back-end's perspective.

```bash
# Through CDN -- compare behavior
curl -X QUERY https://target.com/ \
-H "Content-Type: text/plain" \
-H "Content-Length: 50" \
-d "GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n"

# Direct to origin -- compare Content-Length handling
curl -X QUERY https://origin-ip/ \
-H "Host: target.com" \
-H "Content-Type: text/plain" \
-H "Content-Length: 50" \
-d "GET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n"
```

Divergence in body handling between CDN and origin = smuggling potential. See `te0-request-smuggling` and `h2-waf-bypass` skills for full smuggling methodology.

### 4. Method Routing Confusion

Frameworks that don't recognize QUERY may route it to a catch-all handler with weaker authorization, or fall through to GET/POST handlers with different access controls.

```bash
# Does QUERY reach a different handler than GET?
curl -X QUERY https://target.com/admin/users \
-H "Content-Type: application/json" \
-d '{"page":1}'

# Compare with GET
curl https://target.com/admin/users
```

A 405 response leaks the `Allow` header (supported methods) -- useful recon but not a finding by itself.

## Adoption Gaps (as of July 2026)

| Layer | QUERY Support | Implication |
|---|---|---|
| Node.js / Express | Accepts (custom methods routed via app.all/router.all) | Backend processes QUERY bodies |
| Go net/http | Accepts (any method string handled) | Backend processes QUERY bodies |
| Spring / Rails | Pending / Under discussion | May reject or misroute |
| Cloudflare / Akamai | Co-authored RFC -- QUERY-specific caching behavior untested | CDN may pass through but cache keying unverified |
| Varnish / Squid / HAProxy | Unknown | Highest-signal cache differential targets |
| ModSecurity / AWS WAF / Azure WAF | No documented rules | Likely skip body inspection |
| Imperva / F5 BIG-IP | No public updates | Method whitelists may block or pass without inspection |
| Nginx | Passes through, config-dependent | `limit_except` directives may not include QUERY |

**Test priority:** targets behind Varnish, Squid, HAProxy, or any WAF without documented QUERY support.

## Testing Checklist

```
1. [ ] Does target accept QUERY? (send QUERY, check for non-405 response)
2. [ ] WAF bypass: send blocked POST payload via QUERY -- does it pass?
3. [ ] Cache behavior: send QUERY with body, check cache headers (Age, X-Cache)
4. [ ] Cache key: send two QUERY requests with different bodies to same URL -- same cached response?
5. [ ] Body stripping: send QUERY with body through CDN, verify origin receives body intact
6. [ ] Smuggling: compare QUERY body handling CDN vs direct-to-origin
7. [ ] Routing: does QUERY reach a different handler or authz context than GET/POST?
```

## Related Skills

- **parser-differential-bypass** -- general parser differential methodology
- **h2-waf-bypass** -- WAF bypass via HTTP/2 framing (complementary vector)
- **web-cache-deception-path** -- cache deception via path confusion (different primitive, same cache layer)
- **te0-request-smuggling** -- smuggling methodology applicable to QUERY body disagreements

## References

- [RFC 10008](https://www.rfc-editor.org/rfc/rfc10008.html) -- HTTP QUERY Method specification
- [Hive Security: HTTP QUERY Attack Surface](https://hivesecurity.gitlab.io/blog/http-query-method-rfc-10008-attack-surface/) -- WAF bypass, cache poisoning, smuggling analysis
- [WAFFLED: Parsing Discrepancies in WAFs](https://arxiv.org/html/2503.10846v4) -- general WAF parsing differential research
Loading