Opraveno v upstreamu 27. 10. 2026 Tři neveřejně nahlášené opravy v ai-job-search
ai-job-search: pomalé pravidlo v robots.txt, volné volání curl a gitignore guard, se kterým git nesouhlasil
ai-job-search je framework pro hledání práce postavený na Claude Code: hodnotí inzeráty, upravuje životopisy a píše motivační dopisy. Uživatelé si ho forkují a ukládají do něj vlastní data. Na GitHubu má asi 67 000 hvězd a 21 000 forků. Sken stromu z 19. 10. 2026 označil tři problémy v jeho pomocných nástrojích a každý jsme neveřejně nahlásili přes GitHub s proof of conceptem a návrhem opravy. Správce Mads Lorentzen (MadsLorentzen) všechny tři 27. 10. potvrdil, ohodnotil je níž než my a týž den je opravil v master; v commitech uvádí nás jako zdroj hlášení. Oprava ReDoS je náš navržený matcher.
1. Pravidlo v robots.txt mohlo kontrolu zdržet na minuty
tools/robots_check.py stáhne robots.txt pracovního portálu dřív, než agent přečte inzerát. Funkce _match převáděla každou * v pravidle na regulární výraz .*:
pat = pattern[:-1] if end_anchor else pattern
rx = '^' + ''.join('.*' if c == '*' else re.escape(c) for c in pat) + ('$' if end_anchor else '')
return len(pattern) if re.match(rx, path) else -1
Soubor dodává kontrolovaný web. Pravidlo s mnoha segmenty se zástupnými znaky, které na cestu nesedí, třeba Disallow: /*a*a*a…*b$, pošle backtrackingový regex engine Pythonu do exponenciálního času. Děje se to v hlavním procesu až po návratu curl, takže časový limit curl nepomůže.
Navrhli jsme matcher, který místo regexu prochází tabulku v čase úměrném délce vzoru krát délce cesty. Mads Lorentzen naměřil na aktuálním master 5,6 sekundy při 14 segmentech a náš matcher převzal v pull requestu #779. Podle jeho commitu nenašel diferenciální fuzzing s 200 000 případy proti starému regexovému matcheru žádnou změnu výsledků a tři nové testy hlídají prefixové, ukotvené a přes lomítka jdoucí případy.
2. Tentýž nástroj předával curl libovolné schéma URL
gate() skládala cíl jako scheme://host/robots.txt bez kontroly schématu a _fetch() spouštěla curl -L bez omezení protokolů. Přímé volání s gopher: nebo ftp: došlo do curl beze změny a přesměrování mohlo protokol přepnout.
Správce ukázal, že dosah je užší, než tvrdilo naše hlášení. Složená URL změní file:///etc/passwd na file:///robots.txt, takže se žádný soubor nepřečte; curl už sám odmítá přesměrování na file, scp a smb; tělo odpovědi se nikdy nevypisuje; a hlavní cesta stahování, fetch_page.py, už povolovala jen http(s). Zbyl slepý požadavek a HTTP status. Naši navrženou opravu přesto převzal ve stejném pull requestu: gate() teď u jiného schématu než http(s) nebo u URL bez hostu bezpečně selže a curl dostává --proto =http,https --proto-redir =http,https.
3. Guard osobních dat četl .gitignore jinak než git
Forky projektu obsahují údaje o platu, životopisy a stažené seznamy nabídek a SECURITY.md projektu slibuje, že CI shodí každou změnu, která pravidla .gitignore pro tato data oslabí. check_gitignore() v tools/security_guards.py to dělala porovnáním řádků kořenového .gitignore po jejich oříznutí:
lines = [line.strip() for line in path.read_text(encoding="utf-8").splitlines()]
Git ignoruje jen neescapované mezery na konci řádku. Mezera na začátku je součástí vzoru, takže salary_data.json už salary_data.json neignoruje, zatímco guard mezeru ořízl a prošel. Guard navíc četl jen kořenový soubor, takže .gitignore v podsložce s negací ! mohl osobní soubory vrátit do repozitáře a CI zůstalo zelené.
Mads Lorentzen reprodukoval obě části a ohodnotil problém jako nízký, protože obě změny jsou vidět v revidovaném diffu, ale dodal:
„catching exactly that is the guard’s job.“
Oprava v commitu 0bcfd75 čte řádky stejně jako git a kontroluje negace ve všech .gitignore pod kořenem, se seznamem povolených výjimek. SECURITY.md teď obě pravidla uvádí.
Časová osa
- 19. 10. 2026. Sken stromu v commitu
9c802a4označil tři problémy; proof-of-concept testy potvrdily každý z nich a nahlásili jsme je přes neveřejné hlášení zranitelností na GitHubu, jak žádáSECURITY.mdprojektu. - 27. 10. Mads Lorentzen všechny tři v advisories potvrdil a týž den začlenil opravy: pull request #779 pro
robots_check.pya commit 0bcfd75 pro guard. Oba commity uvádějí naše hlášení a vydání je plánované jako v1.7.4.
Jak to číst
Ani jeden ze tří problémů není díra zneužitelná na dálku. ReDoS zasekne jednu lokální kontrolu, kterou zastaví timeout nebo uživatel. Problém s curl vyžaduje přímé volání a dá jen slepý požadavek. Obejití gitignore vyžaduje změnu sledovaného souboru, kterou by recenzent viděl. Správce každý z nich ohodnotil níž než naše triáž a jeho poznámky hlášení zpřesnily. Hodnota je v nástrojích, které dělají, co bezpečnostní poznámky projektu slibují. Nálezy jsou podněty pro lidi, ne rozsudky.