All API requests require your API key in the Authorization header:
Authorization: Bearer dh_your_api_key_here
Get your API key at /api-keys
http://ec2-98-84-96-127.compute-1.amazonaws.com
curl -X POST http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan \ -H "Authorization: Bearer dh_your_key" \ -F "apk=@your_app.apk"
# Response
{"job_id": "abc-123", "status": "running"}
curl http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan/abc-123 \ -H "Authorization: Bearer dh_your_key"
# Response (running)
{"job_id": "abc-123", "status": "running", "counts": {}}
# Response (done)
{"job_id": "abc-123", "status": "done", "total_findings": 24,
"counts": {"CRITICAL":0,"HIGH":5,"MEDIUM":8,"LOW":6,"INFO":5}}
curl http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan/abc-123/findings \ -H "Authorization: Bearer dh_your_key"
curl http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scans \ -H "Authorization: Bearer dh_your_key"
| Code | Meaning |
|---|---|
202 | Scan submitted successfully |
200 | Success |
401 | Invalid or missing API key |
403 | Plan does not include API access |
429 | Monthly scan limit reached |
404 | Scan not found |
Add this to .github/workflows/security.yml in your repo:
name: DroidHog APK Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
apk-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build APK
run: ./gradlew assembleRelease
- name: Scan with DroidHog
env:
DROIDHOG_API_KEY: ${{ secrets.DROIDHOG_API_KEY }}
run: |
APK=$(find . -name "*.apk" | head -1)
echo "Scanning $APK..."
# Submit scan
RESPONSE=$(curl -s -X POST \
http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan \
-H "Authorization: Bearer $DROIDHOG_API_KEY" \
-F "apk=@$APK")
JOB_ID=$(echo $RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo "Job ID: $JOB_ID"
# Poll until done
for i in $(seq 1 60); do
sleep 10
STATUS=$(curl -s \
http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan/$JOB_ID \
-H "Authorization: Bearer $DROIDHOG_API_KEY")
STATE=$(echo $STATUS | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo "Status: $STATE"
if [ "$STATE" = "done" ]; then
echo $STATUS | python3 -c "
import sys, json
d = json.load(sys.stdin)
c = d.get('counts', {})
print(f'CRITICAL: {c.get(\"CRITICAL\",0)}')
print(f'HIGH: {c.get(\"HIGH\",0)}')
print(f'MEDIUM: {c.get(\"MEDIUM\",0)}')
# Fail CI if CRITICAL or HIGH findings
if c.get('CRITICAL',0) > 0 or c.get('HIGH',0) > 0:
sys.exit(1)
"
break
fi
done
# .gitlab-ci.yml
apk-security-scan:
stage: test
script:
- APK=$(find . -name "*.apk" | head -1)
- |
RESPONSE=$(curl -s -X POST \
http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan \
-H "Authorization: Bearer $DROIDHOG_API_KEY" \
-F "apk=@$APK")
JOB_ID=$(echo $RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
for i in $(seq 1 60); do
sleep 10
STATUS=$(curl -s \
http://ec2-98-84-96-127.compute-1.amazonaws.com/api/v1/scan/$JOB_ID \
-H "Authorization: Bearer $DROIDHOG_API_KEY")
STATE=$(echo $STATUS | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
[ "$STATE" = "done" ] && break
done
echo $STATUS | python3 -c "
import sys,json; d=json.load(sys.stdin); c=d.get('counts',{})
print(f'HIGH={c.get(\"HIGH\",0)} CRITICAL={c.get(\"CRITICAL\",0)}')
sys.exit(1 if c.get('CRITICAL',0)+c.get('HIGH',0) > 0 else 0)"
only:
- main
- merge_requests
import requests, time
API_KEY = "dh_your_key_here"
BASE = "http://ec2-98-84-96-127.compute-1.amazonaws.com"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Submit
r = requests.post(f"{BASE}/api/v1/scan",
headers=HEADERS,
files={"apk": open("app.apk", "rb")})
job_id = r.json()["job_id"]
# Poll
while True:
time.sleep(10)
status = requests.get(f"{BASE}/api/v1/scan/{job_id}", headers=HEADERS).json()
if status["status"] == "done":
break
# Get findings
findings = requests.get(f"{BASE}/api/v1/scan/{job_id}/findings", headers=HEADERS).json()
high = [f for f in findings["findings"] if f["severity"] in ("HIGH","CRITICAL")]
print(f"Found {len(high)} HIGH/CRITICAL issues")