v0.26.0 - Audyt bezpieczenstwa przed v1.0.0
v0.26.0 — Audyt bezpieczenstwa przed v1.0.0
Mini-krok wciskniety przed Krokiem 21 (v1.0.0), na wyrazna prosbe usera: pelny
audyt bezpieczenstwa calej wtyczki (rozpoznanie -> audyt -> poprawki -> testy ->
mutacje -> raport). Zero zmian schematu bazy, zero usunietych plikow, zero nowych
zaleznosci, zero bajtow zmian w assets/.
Najpowazniejsze znalezisko: publiczny /ask pisal do bazy bez limitu
Endpoint POST /aifaq/v1/ask jest z definicji publiczny — gosc pyta bez
logowania. Dwie sciezki wyjscia omijaly wszystkie bramki kosztu, a mimo to
zapisywaly wiersz do wp_aifaq_qa_log:
- trafienie w cache — ta galaz stoi PRZED limiterem gosia (kolejnosc
potoku RagService), wiec bot powtarzajacy jedno pytanie place zero i pisze
w nieskonczonosc; - odbicie o limit/sufit — samo odrzucenie tez wykonywalo INSERT.
Naprawa: tlumik RagService::log_once()/log_marked() — wpis powstaje przy
PIERWSZYM wystapieniu w oknie (1 h), potem cisza. Gosc dalej dostaje identyczna
odpowiedz (200 z cache albo 429); wlasciciel nie traci widocznosci realnie
roznych pytan (kubelek jest per gosc + per pytanie dla cache, per gosc dla
odbic).
Klucz API byl autoladowany
aifaq_settings (niesie klucz Gemini) powstawala przez update_option() bez
trzeciego argumentu, czyli z autoload = yes — sekret ladowal sie do
alloptions przy KAZDYM zadaniu witryny, takze zadaniu gosia. Naprawa: zapis
z autoload = false plus jednorazowa migracja istniejacych instalacji
(Plugin::maybe_harden_options()), ktora rusza WYLACZNIE kolumne autoload —
wartosc opcji nie jest ani kasowana, ani przepisywana, wiec nie ma sciezki
utraty klucza klienta.
Pozostale poprawki
- Naglowek
X-AIFAQ-Crawlbyl nieuwierzytelniona stala"1"i wylaczal
WP-Cron dowolnemu gosciowi (duszenie zadan w tle na witrynie o malym ruchu).
Teraz token zwp_salt(), porownaniehash_equals(). - IDOR — rola narzedzia (
publish_posts) mogla opublikowac cudza generacje
po samymid, obchodzac admin-only historie. Galazidzawezona do
manage_options; UI zawsze wysylapairs, wiec zero skutku dla produktu. - Temat generatora nie mial serwerowego limitu dlugosci (opis mial od K20).
DolozoneMAX_TOPIC_CHARS = 500. - Pytanie gosia szlo do promptu surowe — bez neutralizacji granic sekcji,
ktora chroni temat/opis od K20. Dolozona ta sama obrona (harden_question()). - Eksport Elementora nie escapowal tresci modelu (Elementor renderuje
tab_contentjako HTML, wiec kodowanie JSON tam nie jest ucieczka).
Retencja dziennika pytan gosci
Dolozona osobno, opt-in jak przy historii generowan: qa_log_keep_rows
(0-20000) i qa_log_keep_days (0-3650), oba domyslnie 0 = nic nie kasuj.
wp_aifaq_qa_log rosnie z kazdym pytaniem gosia (nie tylko dzialaniem
wlasciciela), wiec na ruchliwej witrynie bez sprzatania rosnie szybciej niz
historia generacji, ktora retencje mial juz od Kroku 20.
Odbior
runner 42 zestawy — 0 niezaliczonych (nowy segment audyt-bezpieczenstwa-test.php, 53 asercje)
mutacje 8/8 czerwienia (M1-M8: kazda poprawka realnie wykonana)
budzet API: 0 wywolan cala tura statyczna
Pelny raport (10 sekcji, macierz 15 tras REST, LLM security, remaining risks):
plany/AUDYT-BEZPIECZENSTWA-K21.md.
Pozostale ryzyka — decyzje usera
readme.txt/LICENSEwciaz brak — twarda blokada WordPress.org, swiadomie
odlozone do Kroku 21.- Limiter jest kluczowany po IP — gosc z pula adresow dostaje swiezy kubelek
na kazdy adres; zaakceptowane, koszt naprawy przewyzsza zysk przy zamrozonym
kontrakcie K20.
NASTEPNY KROK: Krok 21 — v1.0.0 (audyt juz zrobiony w tym wydaniu, zostaje
RWA i instrukcja wdrozenia + LICENSE/readme.txt).