Fossil SCM

Enforcing allowedAttr limitations in the wiki/MD doc renderers. This fixes an apparent oversight rather than giving new functionality. The allowed attributes were extended to cover www/* and what we've previously documented as allowed.

wyoung 2026-06-21 17:23 UTC trunk
Commit 42a3db61c191e4353354c5558fa2f6b931f888d53f1ad560f57b8755ac1e5d9f
+58 -31
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -140,10 +140,19 @@
140140
#define AMSK_VALUE ((amsk_t)1 << 28)
141141
#define AMSK_VSPACE ((amsk_t)1 << 29)
142142
#define AMSK_WIDTH ((amsk_t)1 << 30)
143143
#define AMSK_CITE ((amsk_t)1 << 31)
144144
#define AMSK_DATETIME ((amsk_t)1 << 32)
145
+#define AMSK_FOR ((amsk_t)1 << 33)
146
+#define AMSK_HIGH ((amsk_t)1 << 34)
147
+#define AMSK_LOW ((amsk_t)1 << 35)
148
+#define AMSK_MAX ((amsk_t)1 << 36)
149
+#define AMSK_MEDIA ((amsk_t)1 << 37)
150
+#define AMSK_MIN ((amsk_t)1 << 38)
151
+#define AMSK_OPTIMUM ((amsk_t)1 << 39)
152
+#define AMSK_SIZES ((amsk_t)1 << 40)
153
+#define AMSK_SRCSET ((amsk_t)1 << 41)
145154
146155
static const struct AllowedAttribute {
147156
const char *zName;
148157
amsk_t iMask;
149158
} aAttribute[] = {
@@ -163,29 +172,29 @@
163172
{ "color", AMSK_COLOR },
164173
{ "colspan", AMSK_COLSPAN },
165174
{ "compact", AMSK_COMPACT },
166175
{ "datetime", AMSK_DATETIME },
167176
{ "face", AMSK_FACE },
168
- { "for", 0 },
177
+ { "for", AMSK_FOR },
169178
{ "height", AMSK_HEIGHT },
170
- { "high", 0 },
179
+ { "high", AMSK_HIGH },
171180
{ "href", AMSK_HREF },
172181
{ "hspace", AMSK_HSPACE },
173182
{ "id", AMSK_ID },
174183
{ "links", AMSK_LINKS },
175
- { "low", 0 },
176
- { "max", 0 },
177
- { "media", 0 },
178
- { "min", 0 },
184
+ { "low", AMSK_LOW },
185
+ { "max", AMSK_MAX },
186
+ { "media", AMSK_MEDIA },
187
+ { "min", AMSK_MIN },
179188
{ "name", AMSK_NAME },
180189
{ "open", AMSK_OPEN },
181
- { "optimum", 0 },
190
+ { "optimum", AMSK_OPTIMUM },
182191
{ "rowspan", AMSK_ROWSPAN },
183192
{ "size", AMSK_SIZE },
184
- { "sizes", 0 },
193
+ { "sizes", AMSK_SIZES },
185194
{ "src", AMSK_SRC },
186
- { "srcset", 0 },
195
+ { "srcset", AMSK_SRCSET },
187196
{ "start", AMSK_START },
188197
{ "style", AMSK_STYLE },
189198
{ "target", AMSK_TARGET },
190199
{ "title", AMSK_TITLE },
191200
{ "type", AMSK_TYPE },
@@ -342,19 +351,20 @@
342351
amsk_t allowedAttr; /* Allowed attributes on this markup */
343352
} aMarkup[] = {
344353
{ 0, MARKUP_INVALID, 0, 0 },
345354
{ "a", MARKUP_A, MUTYPE_HYPERLINK,
346355
AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
347
- AMSK_TITLE},
356
+ AMSK_TITLE|AMSK_ID},
348357
{ "abbr", MARKUP_ABBR, MUTYPE_FONT,
349358
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
350359
{ "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
351360
{ "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
352361
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
353362
{ "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
354363
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
355
- { "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE },
364
+ { "b", MARKUP_B, MUTYPE_FONT,
365
+ AMSK_STYLE|AMSK_ID },
356366
{ "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE },
357367
{ "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE },
358368
{ "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR },
359369
{ "caption", MARKUP_CAPTION, MUTYPE_BLOCK,
360370
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
@@ -369,11 +379,11 @@
369379
{ "del", MARKUP_DEL, MUTYPE_FONT, AMSK_STYLE },
370380
{ "details", MARKUP_DETAILS, MUTYPE_BLOCK,
371381
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_OPEN },
372382
{ "dfn", MARKUP_DFN, MUTYPE_FONT, AMSK_STYLE },
373383
{ "div", MARKUP_DIV, MUTYPE_BLOCK,
374
- AMSK_ID|AMSK_CLASS|AMSK_STYLE },
384
+ AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_ALIGN },
375385
{ "dl", MARKUP_DL, MUTYPE_LIST,
376386
AMSK_COMPACT|AMSK_STYLE },
377387
{ "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE },
378388
{ "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE },
379389
{ "figcaption", MARKUP_FIGCAPTION, MUTYPE_BLOCK,
@@ -383,27 +393,28 @@
383393
{ "font", MARKUP_FONT, MUTYPE_FONT,
384394
AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE },
385395
{ "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK,
386396
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
387397
{ "h1", MARKUP_H1, MUTYPE_BLOCK,
388
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
398
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
389399
{ "h2", MARKUP_H2, MUTYPE_BLOCK,
390
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
400
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
391401
{ "h3", MARKUP_H3, MUTYPE_BLOCK,
392
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
402
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
393403
{ "h4", MARKUP_H4, MUTYPE_BLOCK,
394
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
404
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
395405
{ "h5", MARKUP_H5, MUTYPE_BLOCK,
396
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
406
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
397407
{ "h6", MARKUP_H6, MUTYPE_BLOCK,
398
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
408
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
399409
{ "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK,
400410
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
401411
{ "hr", MARKUP_HR, MUTYPE_SINGLE,
402412
AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH|
403413
AMSK_STYLE|AMSK_CLASS },
404
- { "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE },
414
+ { "i", MARKUP_I, MUTYPE_FONT,
415
+ AMSK_STYLE|AMSK_ID },
405416
{ "img", MARKUP_IMG, MUTYPE_SINGLE,
406417
AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
407418
AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE },
408419
{ "ins", MARKUP_INS, MUTYPE_FONT, AMSK_STYLE },
409420
{ "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE },
@@ -414,33 +425,35 @@
414425
{ "mark", MARKUP_MARK, MUTYPE_FONT,
415426
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
416427
{ "meter", MARKUP_METER, MUTYPE_FONT,
417428
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
418429
{ "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK,
419
- AMSK_ID|AMSK_CLASS|AMSK_STYLE },
430
+ AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
420431
{ "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 },
421432
{ "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },
422433
{ "ol", MARKUP_OL, MUTYPE_LIST,
423434
AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
424435
{ "p", MARKUP_P, MUTYPE_BLOCK,
425
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
436
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID },
426437
{ "picture", MARKUP_PICTURE, MUTYPE_BLOCK,
427438
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
428
- { "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE },
439
+ { "pre", MARKUP_PRE, MUTYPE_BLOCK,
440
+ AMSK_STYLE|AMSK_CLASS },
429441
{ "progress", MARKUP_PROGRESS, MUTYPE_FONT,
430442
AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
431443
{ "q", MARKUP_Q, MUTYPE_FONT,
432444
AMSK_CLASS|AMSK_STYLE|AMSK_CITE },
433
- { "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE },
445
+ { "s", MARKUP_S, MUTYPE_FONT,
446
+ AMSK_STYLE|AMSK_TITLE },
434447
{ "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE },
435448
{ "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK,
436449
AMSK_ID|AMSK_CLASS|AMSK_STYLE },
437450
{ "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE },
438451
{ "source", MARKUP_SOURCE, MUTYPE_SINGLE,
439452
AMSK_TYPE|AMSK_ID|AMSK_CLASS|AMSK_STYLE },
440453
{ "span", MARKUP_SPAN, MUTYPE_BLOCK,
441
- AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
454
+ AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID },
442455
{ "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE },
443456
{ "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE },
444457
{ "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE },
445458
{ "summary", MARKUP_SUMMARY, MUTYPE_BLOCK,
446459
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -451,11 +464,12 @@
451464
AMSK_STYLE },
452465
{ "tbody", MARKUP_TBODY, MUTYPE_BLOCK,
453466
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
454467
{ "td", MARKUP_TD, MUTYPE_TD,
455468
AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
456
- AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
469
+ AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE|
470
+ AMSK_WIDTH },
457471
{ "tfoot", MARKUP_TFOOT, MUTYPE_BLOCK,
458472
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
459473
{ "th", MARKUP_TH, MUTYPE_TD,
460474
AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
461475
AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -463,15 +477,16 @@
463477
AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
464478
{ "time", MARKUP_TIME, MUTYPE_FONT,
465479
AMSK_DATETIME|AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
466480
{ "title", MARKUP_TITLE, MUTYPE_BLOCK, 0 },
467481
{ "tr", MARKUP_TR, MUTYPE_TR,
468
- AMSK_ALIGN|AMSK_BGCOLOR|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
482
+ AMSK_ALIGN|AMSK_BGCOLOR|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE|
483
+ AMSK_ID },
469484
{ "tt", MARKUP_TT, MUTYPE_FONT, AMSK_STYLE },
470485
{ "u", MARKUP_U, MUTYPE_FONT, AMSK_STYLE },
471486
{ "ul", MARKUP_UL, MUTYPE_LIST,
472
- AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
487
+ AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE|AMSK_CLASS },
473488
{ "var", MARKUP_VAR, MUTYPE_FONT, AMSK_STYLE },
474489
{ "wbr", MARKUP_WBR, MUTYPE_SINGLE, 0 },
475490
{ "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL,
476491
AMSK_ID|AMSK_TYPE },
477492
};
@@ -888,10 +903,21 @@
888903
for(i=0; i<p->nAttr; i++){
889904
if( p->aAttr[i].iACode==iACode ) return 1;
890905
}
891906
return 0;
892907
}
908
+
909
+/*
910
+** Return true if attribute iACode is permitted on tag iTag per aMarkup[].
911
+*/
912
+static int attrAllowedOnTag(int iTag, int iACode){
913
+ amsk_t m;
914
+ if( iTag<=0 || iACode<=0 ) return 0;
915
+ m = aAttribute[iACode].iMask;
916
+ if( m==0 ) return 0;
917
+ return (aMarkup[iTag].allowedAttr & m)!=0;
918
+}
893919
894920
/*
895921
** z[] is an HTML markup element - something that begins with '<'.
896922
** Parse this element into the p structure.
897923
**
@@ -920,11 +946,11 @@
920946
zTag[j] = 0;
921947
p->iCode = findTag(zTag);
922948
p->iType = aMarkup[p->iCode].iType;
923949
p->nAttr = 0;
924950
c = 0;
925
- if( z[i]=='-' ){
951
+ if( z[i]=='-' && (aMarkup[p->iCode].allowedAttr & AMSK_ID)!=0 ){
926952
p->aAttr[0].iACode = iACode = ATTR_ID;
927953
i++;
928954
p->aAttr[0].zValue = &z[i];
929955
while( fossil_isalnum(z[i]) ){ i++; }
930956
p->aAttr[0].cTerm = c = z[i];
@@ -940,11 +966,12 @@
940966
if( j<(int)sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]);
941967
i++;
942968
}
943969
zTag[j] = 0;
944970
p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
945
- attrOk = iACode!=0 && !markupHasAttr(p, iACode);
971
+ attrOk = iACode!=0 && !markupHasAttr(p, iACode)
972
+ && attrAllowedOnTag(p->iCode, iACode);
946973
while( fossil_isspace(z[i]) ){ z++; }
947974
if( z[i]!='=' ){
948975
p->aAttr[p->nAttr].zValue = 0;
949976
p->aAttr[p->nAttr].cTerm = 0;
950977
c = 0;
@@ -3053,12 +3080,12 @@
30533080
** are made:
30543081
**
30553082
** 1. Remove any elements that are not on the AllowedMarkup list.
30563083
** (ex: <script>, <form>, etc.)
30573084
**
3058
-** 2. Remove any attributes that are not on the AllowedMarkup list.
3059
-** (ex: onload=, etc.)
3085
+** 2. Remove any attributes that are not on the AllowedMarkup list
3086
+** for that tag. (ex: onload=, etc.)
30603087
**
30613088
** 3. Omit any surplus close-tags. This prevents the script from
30623089
** terminating an <div> or similar in the outer context.
30633090
**
30643091
** 4. Insert additional close-tags as necessary so that any
30653092
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -140,10 +140,19 @@
140 #define AMSK_VALUE ((amsk_t)1 << 28)
141 #define AMSK_VSPACE ((amsk_t)1 << 29)
142 #define AMSK_WIDTH ((amsk_t)1 << 30)
143 #define AMSK_CITE ((amsk_t)1 << 31)
144 #define AMSK_DATETIME ((amsk_t)1 << 32)
 
 
 
 
 
 
 
 
 
145
146 static const struct AllowedAttribute {
147 const char *zName;
148 amsk_t iMask;
149 } aAttribute[] = {
@@ -163,29 +172,29 @@
163 { "color", AMSK_COLOR },
164 { "colspan", AMSK_COLSPAN },
165 { "compact", AMSK_COMPACT },
166 { "datetime", AMSK_DATETIME },
167 { "face", AMSK_FACE },
168 { "for", 0 },
169 { "height", AMSK_HEIGHT },
170 { "high", 0 },
171 { "href", AMSK_HREF },
172 { "hspace", AMSK_HSPACE },
173 { "id", AMSK_ID },
174 { "links", AMSK_LINKS },
175 { "low", 0 },
176 { "max", 0 },
177 { "media", 0 },
178 { "min", 0 },
179 { "name", AMSK_NAME },
180 { "open", AMSK_OPEN },
181 { "optimum", 0 },
182 { "rowspan", AMSK_ROWSPAN },
183 { "size", AMSK_SIZE },
184 { "sizes", 0 },
185 { "src", AMSK_SRC },
186 { "srcset", 0 },
187 { "start", AMSK_START },
188 { "style", AMSK_STYLE },
189 { "target", AMSK_TARGET },
190 { "title", AMSK_TITLE },
191 { "type", AMSK_TYPE },
@@ -342,19 +351,20 @@
342 amsk_t allowedAttr; /* Allowed attributes on this markup */
343 } aMarkup[] = {
344 { 0, MARKUP_INVALID, 0, 0 },
345 { "a", MARKUP_A, MUTYPE_HYPERLINK,
346 AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
347 AMSK_TITLE},
348 { "abbr", MARKUP_ABBR, MUTYPE_FONT,
349 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
350 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
351 { "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
352 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
353 { "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
354 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
355 { "b", MARKUP_B, MUTYPE_FONT, AMSK_STYLE },
 
356 { "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE },
357 { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE },
358 { "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR },
359 { "caption", MARKUP_CAPTION, MUTYPE_BLOCK,
360 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
@@ -369,11 +379,11 @@
369 { "del", MARKUP_DEL, MUTYPE_FONT, AMSK_STYLE },
370 { "details", MARKUP_DETAILS, MUTYPE_BLOCK,
371 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_OPEN },
372 { "dfn", MARKUP_DFN, MUTYPE_FONT, AMSK_STYLE },
373 { "div", MARKUP_DIV, MUTYPE_BLOCK,
374 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
375 { "dl", MARKUP_DL, MUTYPE_LIST,
376 AMSK_COMPACT|AMSK_STYLE },
377 { "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE },
378 { "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE },
379 { "figcaption", MARKUP_FIGCAPTION, MUTYPE_BLOCK,
@@ -383,27 +393,28 @@
383 { "font", MARKUP_FONT, MUTYPE_FONT,
384 AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE },
385 { "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK,
386 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
387 { "h1", MARKUP_H1, MUTYPE_BLOCK,
388 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
389 { "h2", MARKUP_H2, MUTYPE_BLOCK,
390 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
391 { "h3", MARKUP_H3, MUTYPE_BLOCK,
392 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
393 { "h4", MARKUP_H4, MUTYPE_BLOCK,
394 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
395 { "h5", MARKUP_H5, MUTYPE_BLOCK,
396 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
397 { "h6", MARKUP_H6, MUTYPE_BLOCK,
398 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
399 { "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK,
400 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
401 { "hr", MARKUP_HR, MUTYPE_SINGLE,
402 AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH|
403 AMSK_STYLE|AMSK_CLASS },
404 { "i", MARKUP_I, MUTYPE_FONT, AMSK_STYLE },
 
405 { "img", MARKUP_IMG, MUTYPE_SINGLE,
406 AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
407 AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE },
408 { "ins", MARKUP_INS, MUTYPE_FONT, AMSK_STYLE },
409 { "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE },
@@ -414,33 +425,35 @@
414 { "mark", MARKUP_MARK, MUTYPE_FONT,
415 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
416 { "meter", MARKUP_METER, MUTYPE_FONT,
417 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
418 { "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK,
419 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
420 { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 },
421 { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },
422 { "ol", MARKUP_OL, MUTYPE_LIST,
423 AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
424 { "p", MARKUP_P, MUTYPE_BLOCK,
425 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
426 { "picture", MARKUP_PICTURE, MUTYPE_BLOCK,
427 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
428 { "pre", MARKUP_PRE, MUTYPE_BLOCK, AMSK_STYLE },
 
429 { "progress", MARKUP_PROGRESS, MUTYPE_FONT,
430 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
431 { "q", MARKUP_Q, MUTYPE_FONT,
432 AMSK_CLASS|AMSK_STYLE|AMSK_CITE },
433 { "s", MARKUP_S, MUTYPE_FONT, AMSK_STYLE },
 
434 { "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE },
435 { "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK,
436 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
437 { "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE },
438 { "source", MARKUP_SOURCE, MUTYPE_SINGLE,
439 AMSK_TYPE|AMSK_ID|AMSK_CLASS|AMSK_STYLE },
440 { "span", MARKUP_SPAN, MUTYPE_BLOCK,
441 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
442 { "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE },
443 { "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE },
444 { "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE },
445 { "summary", MARKUP_SUMMARY, MUTYPE_BLOCK,
446 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -451,11 +464,12 @@
451 AMSK_STYLE },
452 { "tbody", MARKUP_TBODY, MUTYPE_BLOCK,
453 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
454 { "td", MARKUP_TD, MUTYPE_TD,
455 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
456 AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
 
457 { "tfoot", MARKUP_TFOOT, MUTYPE_BLOCK,
458 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
459 { "th", MARKUP_TH, MUTYPE_TD,
460 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
461 AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -463,15 +477,16 @@
463 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
464 { "time", MARKUP_TIME, MUTYPE_FONT,
465 AMSK_DATETIME|AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
466 { "title", MARKUP_TITLE, MUTYPE_BLOCK, 0 },
467 { "tr", MARKUP_TR, MUTYPE_TR,
468 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
 
469 { "tt", MARKUP_TT, MUTYPE_FONT, AMSK_STYLE },
470 { "u", MARKUP_U, MUTYPE_FONT, AMSK_STYLE },
471 { "ul", MARKUP_UL, MUTYPE_LIST,
472 AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
473 { "var", MARKUP_VAR, MUTYPE_FONT, AMSK_STYLE },
474 { "wbr", MARKUP_WBR, MUTYPE_SINGLE, 0 },
475 { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL,
476 AMSK_ID|AMSK_TYPE },
477 };
@@ -888,10 +903,21 @@
888 for(i=0; i<p->nAttr; i++){
889 if( p->aAttr[i].iACode==iACode ) return 1;
890 }
891 return 0;
892 }
 
 
 
 
 
 
 
 
 
 
 
893
894 /*
895 ** z[] is an HTML markup element - something that begins with '<'.
896 ** Parse this element into the p structure.
897 **
@@ -920,11 +946,11 @@
920 zTag[j] = 0;
921 p->iCode = findTag(zTag);
922 p->iType = aMarkup[p->iCode].iType;
923 p->nAttr = 0;
924 c = 0;
925 if( z[i]=='-' ){
926 p->aAttr[0].iACode = iACode = ATTR_ID;
927 i++;
928 p->aAttr[0].zValue = &z[i];
929 while( fossil_isalnum(z[i]) ){ i++; }
930 p->aAttr[0].cTerm = c = z[i];
@@ -940,11 +966,12 @@
940 if( j<(int)sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]);
941 i++;
942 }
943 zTag[j] = 0;
944 p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
945 attrOk = iACode!=0 && !markupHasAttr(p, iACode);
 
946 while( fossil_isspace(z[i]) ){ z++; }
947 if( z[i]!='=' ){
948 p->aAttr[p->nAttr].zValue = 0;
949 p->aAttr[p->nAttr].cTerm = 0;
950 c = 0;
@@ -3053,12 +3080,12 @@
3053 ** are made:
3054 **
3055 ** 1. Remove any elements that are not on the AllowedMarkup list.
3056 ** (ex: <script>, <form>, etc.)
3057 **
3058 ** 2. Remove any attributes that are not on the AllowedMarkup list.
3059 ** (ex: onload=, etc.)
3060 **
3061 ** 3. Omit any surplus close-tags. This prevents the script from
3062 ** terminating an <div> or similar in the outer context.
3063 **
3064 ** 4. Insert additional close-tags as necessary so that any
3065
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -140,10 +140,19 @@
140 #define AMSK_VALUE ((amsk_t)1 << 28)
141 #define AMSK_VSPACE ((amsk_t)1 << 29)
142 #define AMSK_WIDTH ((amsk_t)1 << 30)
143 #define AMSK_CITE ((amsk_t)1 << 31)
144 #define AMSK_DATETIME ((amsk_t)1 << 32)
145 #define AMSK_FOR ((amsk_t)1 << 33)
146 #define AMSK_HIGH ((amsk_t)1 << 34)
147 #define AMSK_LOW ((amsk_t)1 << 35)
148 #define AMSK_MAX ((amsk_t)1 << 36)
149 #define AMSK_MEDIA ((amsk_t)1 << 37)
150 #define AMSK_MIN ((amsk_t)1 << 38)
151 #define AMSK_OPTIMUM ((amsk_t)1 << 39)
152 #define AMSK_SIZES ((amsk_t)1 << 40)
153 #define AMSK_SRCSET ((amsk_t)1 << 41)
154
155 static const struct AllowedAttribute {
156 const char *zName;
157 amsk_t iMask;
158 } aAttribute[] = {
@@ -163,29 +172,29 @@
172 { "color", AMSK_COLOR },
173 { "colspan", AMSK_COLSPAN },
174 { "compact", AMSK_COMPACT },
175 { "datetime", AMSK_DATETIME },
176 { "face", AMSK_FACE },
177 { "for", AMSK_FOR },
178 { "height", AMSK_HEIGHT },
179 { "high", AMSK_HIGH },
180 { "href", AMSK_HREF },
181 { "hspace", AMSK_HSPACE },
182 { "id", AMSK_ID },
183 { "links", AMSK_LINKS },
184 { "low", AMSK_LOW },
185 { "max", AMSK_MAX },
186 { "media", AMSK_MEDIA },
187 { "min", AMSK_MIN },
188 { "name", AMSK_NAME },
189 { "open", AMSK_OPEN },
190 { "optimum", AMSK_OPTIMUM },
191 { "rowspan", AMSK_ROWSPAN },
192 { "size", AMSK_SIZE },
193 { "sizes", AMSK_SIZES },
194 { "src", AMSK_SRC },
195 { "srcset", AMSK_SRCSET },
196 { "start", AMSK_START },
197 { "style", AMSK_STYLE },
198 { "target", AMSK_TARGET },
199 { "title", AMSK_TITLE },
200 { "type", AMSK_TYPE },
@@ -342,19 +351,20 @@
351 amsk_t allowedAttr; /* Allowed attributes on this markup */
352 } aMarkup[] = {
353 { 0, MARKUP_INVALID, 0, 0 },
354 { "a", MARKUP_A, MUTYPE_HYPERLINK,
355 AMSK_HREF|AMSK_NAME|AMSK_CLASS|AMSK_TARGET|AMSK_STYLE|
356 AMSK_TITLE|AMSK_ID},
357 { "abbr", MARKUP_ABBR, MUTYPE_FONT,
358 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
359 { "address", MARKUP_ADDRESS, MUTYPE_BLOCK, AMSK_STYLE },
360 { "article", MARKUP_HTML5_ARTICLE, MUTYPE_BLOCK,
361 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
362 { "aside", MARKUP_HTML5_ASIDE, MUTYPE_BLOCK,
363 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
364 { "b", MARKUP_B, MUTYPE_FONT,
365 AMSK_STYLE|AMSK_ID },
366 { "big", MARKUP_BIG, MUTYPE_FONT, AMSK_STYLE },
367 { "blockquote", MARKUP_BLOCKQUOTE, MUTYPE_BLOCK, AMSK_STYLE },
368 { "br", MARKUP_BR, MUTYPE_SINGLE, AMSK_CLEAR },
369 { "caption", MARKUP_CAPTION, MUTYPE_BLOCK,
370 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
@@ -369,11 +379,11 @@
379 { "del", MARKUP_DEL, MUTYPE_FONT, AMSK_STYLE },
380 { "details", MARKUP_DETAILS, MUTYPE_BLOCK,
381 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_OPEN },
382 { "dfn", MARKUP_DFN, MUTYPE_FONT, AMSK_STYLE },
383 { "div", MARKUP_DIV, MUTYPE_BLOCK,
384 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_ALIGN },
385 { "dl", MARKUP_DL, MUTYPE_LIST,
386 AMSK_COMPACT|AMSK_STYLE },
387 { "dt", MARKUP_DT, MUTYPE_LI, AMSK_STYLE },
388 { "em", MARKUP_EM, MUTYPE_FONT, AMSK_STYLE },
389 { "figcaption", MARKUP_FIGCAPTION, MUTYPE_BLOCK,
@@ -383,27 +393,28 @@
393 { "font", MARKUP_FONT, MUTYPE_FONT,
394 AMSK_COLOR|AMSK_FACE|AMSK_SIZE|AMSK_STYLE },
395 { "footer", MARKUP_HTML5_FOOTER, MUTYPE_BLOCK,
396 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
397 { "h1", MARKUP_H1, MUTYPE_BLOCK,
398 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
399 { "h2", MARKUP_H2, MUTYPE_BLOCK,
400 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
401 { "h3", MARKUP_H3, MUTYPE_BLOCK,
402 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
403 { "h4", MARKUP_H4, MUTYPE_BLOCK,
404 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
405 { "h5", MARKUP_H5, MUTYPE_BLOCK,
406 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
407 { "h6", MARKUP_H6, MUTYPE_BLOCK,
408 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID|AMSK_NAME },
409 { "header", MARKUP_HTML5_HEADER, MUTYPE_BLOCK,
410 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
411 { "hr", MARKUP_HR, MUTYPE_SINGLE,
412 AMSK_ALIGN|AMSK_COLOR|AMSK_SIZE|AMSK_WIDTH|
413 AMSK_STYLE|AMSK_CLASS },
414 { "i", MARKUP_I, MUTYPE_FONT,
415 AMSK_STYLE|AMSK_ID },
416 { "img", MARKUP_IMG, MUTYPE_SINGLE,
417 AMSK_ALIGN|AMSK_ALT|AMSK_BORDER|AMSK_HEIGHT|
418 AMSK_HSPACE|AMSK_SRC|AMSK_VSPACE|AMSK_WIDTH|AMSK_STYLE },
419 { "ins", MARKUP_INS, MUTYPE_FONT, AMSK_STYLE },
420 { "kbd", MARKUP_KBD, MUTYPE_FONT, AMSK_STYLE },
@@ -414,33 +425,35 @@
425 { "mark", MARKUP_MARK, MUTYPE_FONT,
426 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
427 { "meter", MARKUP_METER, MUTYPE_FONT,
428 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
429 { "nav", MARKUP_HTML5_NAV, MUTYPE_BLOCK,
430 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
431 { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 },
432 { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },
433 { "ol", MARKUP_OL, MUTYPE_LIST,
434 AMSK_START|AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE },
435 { "p", MARKUP_P, MUTYPE_BLOCK,
436 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID },
437 { "picture", MARKUP_PICTURE, MUTYPE_BLOCK,
438 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
439 { "pre", MARKUP_PRE, MUTYPE_BLOCK,
440 AMSK_STYLE|AMSK_CLASS },
441 { "progress", MARKUP_PROGRESS, MUTYPE_FONT,
442 AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_VALUE },
443 { "q", MARKUP_Q, MUTYPE_FONT,
444 AMSK_CLASS|AMSK_STYLE|AMSK_CITE },
445 { "s", MARKUP_S, MUTYPE_FONT,
446 AMSK_STYLE|AMSK_TITLE },
447 { "samp", MARKUP_SAMP, MUTYPE_FONT, AMSK_STYLE },
448 { "section", MARKUP_HTML5_SECTION, MUTYPE_BLOCK,
449 AMSK_ID|AMSK_CLASS|AMSK_STYLE },
450 { "small", MARKUP_SMALL, MUTYPE_FONT, AMSK_STYLE },
451 { "source", MARKUP_SOURCE, MUTYPE_SINGLE,
452 AMSK_TYPE|AMSK_ID|AMSK_CLASS|AMSK_STYLE },
453 { "span", MARKUP_SPAN, MUTYPE_BLOCK,
454 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE|AMSK_ID },
455 { "strike", MARKUP_STRIKE, MUTYPE_FONT, AMSK_STYLE },
456 { "strong", MARKUP_STRONG, MUTYPE_FONT, AMSK_STYLE },
457 { "sub", MARKUP_SUB, MUTYPE_FONT, AMSK_STYLE },
458 { "summary", MARKUP_SUMMARY, MUTYPE_BLOCK,
459 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -451,11 +464,12 @@
464 AMSK_STYLE },
465 { "tbody", MARKUP_TBODY, MUTYPE_BLOCK,
466 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
467 { "td", MARKUP_TD, MUTYPE_TD,
468 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
469 AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE|
470 AMSK_WIDTH },
471 { "tfoot", MARKUP_TFOOT, MUTYPE_BLOCK,
472 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
473 { "th", MARKUP_TH, MUTYPE_TD,
474 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_COLSPAN|
475 AMSK_ROWSPAN|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE },
@@ -463,15 +477,16 @@
477 AMSK_ALIGN|AMSK_CLASS|AMSK_STYLE },
478 { "time", MARKUP_TIME, MUTYPE_FONT,
479 AMSK_DATETIME|AMSK_ID|AMSK_CLASS|AMSK_STYLE|AMSK_TITLE },
480 { "title", MARKUP_TITLE, MUTYPE_BLOCK, 0 },
481 { "tr", MARKUP_TR, MUTYPE_TR,
482 AMSK_ALIGN|AMSK_BGCOLOR|AMSK_VALIGN|AMSK_CLASS|AMSK_STYLE|
483 AMSK_ID },
484 { "tt", MARKUP_TT, MUTYPE_FONT, AMSK_STYLE },
485 { "u", MARKUP_U, MUTYPE_FONT, AMSK_STYLE },
486 { "ul", MARKUP_UL, MUTYPE_LIST,
487 AMSK_TYPE|AMSK_COMPACT|AMSK_STYLE|AMSK_CLASS },
488 { "var", MARKUP_VAR, MUTYPE_FONT, AMSK_STYLE },
489 { "wbr", MARKUP_WBR, MUTYPE_SINGLE, 0 },
490 { "verbatim", MARKUP_VERBATIM, MUTYPE_SPECIAL,
491 AMSK_ID|AMSK_TYPE },
492 };
@@ -888,10 +903,21 @@
903 for(i=0; i<p->nAttr; i++){
904 if( p->aAttr[i].iACode==iACode ) return 1;
905 }
906 return 0;
907 }
908
909 /*
910 ** Return true if attribute iACode is permitted on tag iTag per aMarkup[].
911 */
912 static int attrAllowedOnTag(int iTag, int iACode){
913 amsk_t m;
914 if( iTag<=0 || iACode<=0 ) return 0;
915 m = aAttribute[iACode].iMask;
916 if( m==0 ) return 0;
917 return (aMarkup[iTag].allowedAttr & m)!=0;
918 }
919
920 /*
921 ** z[] is an HTML markup element - something that begins with '<'.
922 ** Parse this element into the p structure.
923 **
@@ -920,11 +946,11 @@
946 zTag[j] = 0;
947 p->iCode = findTag(zTag);
948 p->iType = aMarkup[p->iCode].iType;
949 p->nAttr = 0;
950 c = 0;
951 if( z[i]=='-' && (aMarkup[p->iCode].allowedAttr & AMSK_ID)!=0 ){
952 p->aAttr[0].iACode = iACode = ATTR_ID;
953 i++;
954 p->aAttr[0].zValue = &z[i];
955 while( fossil_isalnum(z[i]) ){ i++; }
956 p->aAttr[0].cTerm = c = z[i];
@@ -940,11 +966,12 @@
966 if( j<(int)sizeof(zTag)-1 ) zTag[j++] = fossil_tolower(z[i]);
967 i++;
968 }
969 zTag[j] = 0;
970 p->aAttr[p->nAttr].iACode = iACode = findAttr(zTag);
971 attrOk = iACode!=0 && !markupHasAttr(p, iACode)
972 && attrAllowedOnTag(p->iCode, iACode);
973 while( fossil_isspace(z[i]) ){ z++; }
974 if( z[i]!='=' ){
975 p->aAttr[p->nAttr].zValue = 0;
976 p->aAttr[p->nAttr].cTerm = 0;
977 c = 0;
@@ -3053,12 +3080,12 @@
3080 ** are made:
3081 **
3082 ** 1. Remove any elements that are not on the AllowedMarkup list.
3083 ** (ex: <script>, <form>, etc.)
3084 **
3085 ** 2. Remove any attributes that are not on the AllowedMarkup list
3086 ** for that tag. (ex: onload=, etc.)
3087 **
3088 ** 3. Omit any surplus close-tags. This prevents the script from
3089 ** terminating an <div> or similar in the outer context.
3090 **
3091 ** 4. Insert additional close-tags as necessary so that any
3092
--- www/changes.wiki
+++ www/changes.wiki
@@ -22,10 +22,15 @@
2222
capability.
2323
<li> Add the "[/help/attachment-size-limit|attachment-size-limit]" setting
2424
to limit the size of file attachments to wiki pages, tech notes,
2525
tickets, and forum posts.
2626
<li> Addded several HTML5 tags deemed harmless to the MD/wiki allowlists.
27
+ <li> Enforcing the allowed attribute list in MD/wiki doc rendering, as
28
+ was always intended. This change will not break existing docs
29
+ outright; because it strips disallowed attributes — e.g. &lt;h1
30
+ bogus="nonsense"&gt; — from allowed elements, existing misuses
31
+ may go silently unnoticed. Be warned.
2732
</ol>
2833
2934
<h2 id='v2_28'>Changes for version 2.28 (2026-03-11)</h2><ol>
3035
<li> Improvements to [./antibot.wiki|anti-robot defenses]:<ol type="a">
3136
<li> The default configuration now allows robots to download any tarball
3237
--- www/changes.wiki
+++ www/changes.wiki
@@ -22,10 +22,15 @@
22 capability.
23 <li> Add the "[/help/attachment-size-limit|attachment-size-limit]" setting
24 to limit the size of file attachments to wiki pages, tech notes,
25 tickets, and forum posts.
26 <li> Addded several HTML5 tags deemed harmless to the MD/wiki allowlists.
 
 
 
 
 
27 </ol>
28
29 <h2 id='v2_28'>Changes for version 2.28 (2026-03-11)</h2><ol>
30 <li> Improvements to [./antibot.wiki|anti-robot defenses]:<ol type="a">
31 <li> The default configuration now allows robots to download any tarball
32
--- www/changes.wiki
+++ www/changes.wiki
@@ -22,10 +22,15 @@
22 capability.
23 <li> Add the "[/help/attachment-size-limit|attachment-size-limit]" setting
24 to limit the size of file attachments to wiki pages, tech notes,
25 tickets, and forum posts.
26 <li> Addded several HTML5 tags deemed harmless to the MD/wiki allowlists.
27 <li> Enforcing the allowed attribute list in MD/wiki doc rendering, as
28 was always intended. This change will not break existing docs
29 outright; because it strips disallowed attributes — e.g. &lt;h1
30 bogus="nonsense"&gt; — from allowed elements, existing misuses
31 may go silently unnoticed. Be warned.
32 </ol>
33
34 <h2 id='v2_28'>Changes for version 2.28 (2026-03-11)</h2><ol>
35 <li> Improvements to [./antibot.wiki|anti-robot defenses]:<ol type="a">
36 <li> The default configuration now allows robots to download any tarball
37

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button