--- name: llm-vision-captcha description: Bypass visual captchas with multi-model LLM voting. category: security triggers: - "капча" - "captcha solver" - "arkose bypass" - "funcaptcha" - "agent captcha" - "визуальный солвер" - "обойти капчу через LLM" - "multi-model voting captcha" --- # LLM Vision Captcha Solver Use multiple vision-capable LLMs in parallel to vote on visual captcha solutions — bypasses Arkose FunCaptcha, hCaptcha, and similar visual challenges without paid captcha-solving services. ## When to Use - Arkose FunCaptcha on GitHub signup, xAI, or any protected page - Paid captcha services (CapSolver, YesCaptcha, 2captcha) are unavailable or too slow - You have vision LLM API access (Aurora gateway, OpenRouter, direct provider keys) - The captcha is image-based (not audio/text) - Self-hosted turnkey solver wanted instead of custom voting code → `references/self-hosted-solver-and-free-quota-2026-09-30.md` (waguriagentic/captcha-solver: 11 types incl. arkose/datadome/turnstile, free Mistral vision backend, verified deployment recipe + free-quota API catalog) - **hCaptcha on a live registration farm** → same reference file, section "hCaptcha battle-tested": `real_page:true` payload contract, force-click checkbox cascade, rotation-task prompt, stale-sidecar/port traps, paid-solver pre-audit, three-layer vision-model config (mistral default + solve.py env + watchdog extra_env), timeout-chain ordering (client > payload > server), and empty-task-text diagnosis. The free sidecar solves plain grid hCaptcha, but rotation/drag variants yield ≈0 even when the checkbox opens, the challenge frame loads and grid cells get picked — hCaptcha silently rejects the answers and the token comes back empty after the full timeout. Audit the ACTUAL challenge type on the target before promising a reg throughput; on rotation/drag the free path is not a substitute for a paid solver. ## Core Pattern: Multi-Model Voting ``` 1. Screenshot captcha challenge 2. Local PIL image enhancement (Lanczos upscale + sharpen + contrast) 3. Detect puzzle variant from challenge text 4. Screenshot all candidate answers → stitch into numbered grid 5. Parallel query to 3-4 vision models with identical prompt 6. Parse ANSWER=N from each response 7. Majority vote (tiebreak: model priority order) 8. Auto-click winning answer 9. Save annotated review image for debugging ``` ## Model Pool (by accuracy on captcha tasks) | Priority | Model | Notes | |---|---|---| | 1 | gemini-3.5-flash | Most accurate on orientation/matching | | 2 | gpt-5.5 | Strong all-rounder | | 3 | gemini-3.1-pro | Good on sequences | | 4 | claude-opus-4.8 | Weakest on these images, lowest weight | All models run in parallel via ThreadPoolExecutor with a 55s deadline (Arkose timeout ~60s). ## Implementation Essentials ### 1. Image Enhancement (before sending to LLM) Critical: compressed JPEG with size limits. PNG grids of 7 stitched 3D images hit 13MB — HTTP timeout guaranteed. ```python from PIL import Image, ImageEnhance, ImageFilter im = Image.open(path).convert("RGB") im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS) r = 1600 / max(im.width, im.height) if max(im.width, im.height) > 1600 else 1 if r < 1: im = im.resize((int(im.width*r), int(im.height*r)), Image.LANCZOS) im = im.filter(ImageFilter.MedianFilter(size=3)) im = ImageEnhance.Contrast(im).enhance(1.6) im = ImageEnhance.Brightness(im).enhance(1.15) im = ImageEnhance.Sharpness(im).enhance(2.2) im = im.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=2)) im.save(path, "JPEG", quality=82) ``` ### 2. Candidate Grid Stitching Stitch N candidate images into one labeled grid with numbered cells. Add reference image at top if available. LLM compares all options in one call. ### 3. Parallel Query with Refusal Detection ```python _REFUSAL_MARKERS = ( "cannot fulfill", "can't fulfill", "cannot assist", "i am unable", "i'm unable", "safety guidelines", "not able to help", "cannot help with that", ) def _looks_like_refusal(text): if not text: return True return any(m in text.lower() for m in _REFUSAL_MARKERS) with ThreadPoolExecutor(max_workers=4) as ex: futs = {ex.submit(query_model, args): name for args in VOTER_MODELS} for fut in as_completed(futs, timeout=55): txt = fut.result() if not _looks_like_refusal(txt): a = parse_answer(txt) # regex: ANSWER\s*=\s*(\d+) answers.append(a) ``` ### 4. Gateway Flexibility Support both OpenAI-compatible (`/v1/chat/completions`) and Anthropic-native (`/v1/messages`) APIs. Detect by URL pattern. ### 5. Review Annotation Draw colored boxes on grid image: RED = final vote, colored per-model = individual votes, footer = model→answer legend. Saves to `screenshots/REVIEW_rN.png`. ## Captcha Variant Detection Parse challenge text for puzzle type: - **sequence**: 4 icons in sequential rings → vote per ring - **rotate**: 3D orientation matching → vote rotation - **character**: figure on grid → HARDEST, consider skip - **wires**: connect wires to icons → vote pairing ## Aurora Gateway Integration ```env VISION_API_BASE=http://127.0.0.1:8080 VISION_API_KEY=enigothbreach2026master VOTE_ZZ_BASE=http://127.0.0.1:8080 VOTE_ZZ_KEY=enigothbreach2026master VOTE_GPT_KEY=enigothbreach2026master ``` Aurora (557 models, 111 providers) routes to live dashscope/google/groq keys. **VALIDATED 2026-09-30** — repo module works on Aurora unmodified: point the env vars above at the gateway, override `AC.VOTER_MODELS` with `(base, key, model_id)` tuples, and `vote_answer()` returns a correct majority in ~7s. Verified: gemini-3.6-flash ✅, gemini-3.1-pro ✅, qwen-vl-max ✅ (all 3 voted correctly on a 4-tile match fixture); claude-sonnet-4-6 returned empty content via Aurora (refusal filter drops it cleanly — 3-model quorum still wins). Function map: `ask_vision`, `vote_answer`, `vote_score`, `stitch_options_grid`, `enhance_local`, `parse_json_answer`, `_looks_like_refusal`, `gh_pick_prompt`. **Aurora startup pitfall:** `./aurora.exe --config configs/config.yaml` exits immediately (prints help and dies). Working start: `set -a; source .env; set +a; AURORA_CONFIG_PATH=C:/Users/User/aurora-gateway/configs/config.yaml ./aurora.exe` in background, then poll `/v1/models` up to 25s (startup is slow). Run the verification script any time the stack changes: `scripts/test_agent_captcha_aurora.py` (local function tests + live voting round, needs repo clone at `REPO_PATH` or default `C:/Users/User/tmp/reg-factory-github`). Test detail: `references/voting-test-aurora-2026-09-30.md`. ## Pitfalls - **Payload size**: PNG grids hit 13MB → timeout. JPEG compress with max_side=1600. - **wag-solver apikey.txt**: self-hosted waguriagentic/captcha-solver 500s (Errno 2) until `common/apikey.txt` exists; first solve blocks ~15min on a 535MB cloakbrowser Chromium download — background + poll the process log, never kill mid-download. - **Model refusal**: Claude refuses captcha tasks. Filter via _REFUSAL_MARKERS. - **Deadline race**: Arkose ~60s timeout. Voting deadline 55s max. - **GitHub blob req**: GitHub Arkose needs data-exchange blob from `#funcaptcha[data-data-exchange-payload]`. - **Character variant**: Lowest success rate. Skip and retry with new window. - **Slow models**: Per-model timeout 35s. - **Paid-solver pre-audit must be createTask, not balance**: a positive balance in a scan can coexist with `ERROR_KEY_DOES_NOT_EXIST` on createTask (banned/orphaned account) — the key is unusable regardless of the shown funds. Also verify the provider still supports the exact task type: CapMonster dropped hCaptcha (`ERROR_TASK_NOT_SUPPORTED` on both proxyless and proxied variants) while still accepting recaptcha/turnstile/funcaptcha. One live createTask with the real sitekey is the only valid proof before funding or integrating a solver. ## Source Full impl: https://github.com/GoubaLab/reg-factory-github/blob/main/common/agent_captcha.py (809 lines) ## Related - `bypass-ai` — captcha bypass via paid services - `anti-detection-browser` — browser fingerprint evasion - `fork-analyzer` — repo audit workflow