Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Mark some TH1 inputs that can be controlled by the user as tainted. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | th1-taint |
| Files: | files | file ages | folders |
| SHA3-256: |
2742682720c692ca916c034da28baf69 |
| User & Date: | drh 2025-04-19 19:08:06.942 |
Context
|
2025-04-19
| ||
| 19:18 | Update the default ticket configuration to avoid sending out text that seems tainted. There are no actual XSS issues here, but these changes do add an extra margin of safety. ... (check-in: 5d17ced68d user: drh tags: th1-taint) | |
| 19:08 | Mark some TH1 inputs that can be controlled by the user as tainted. ... (check-in: 2742682720 user: drh tags: th1-taint) | |
| 18:43 | The taint markings and detection now appears to be working. ... (check-in: d1bb87bcfd user: drh tags: th1-taint) | |
Changes
Changes to src/browse.c.
| ︙ | ︙ | |||
203 204 205 206 207 208 209 |
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
if( bDocDir ) zCI = mprintf("%S", zUuid);
| | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI))!=0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
if( bDocDir ) zCI = mprintf("%S", zUuid);
Th_StoreUnsafe("current_checkin", zCI);
}else{
zCI = 0;
}
}
assert( isSymbolicCI==0 || (zCI!=0 && zCI[0]!=0) );
if( zD==0 ){
|
| ︙ | ︙ | |||
769 770 771 772 773 774 775 |
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
zNow = db_text("", "SELECT datetime(mtime,toLocal())"
" FROM event WHERE objid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
| | | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
rNow = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
zNow = db_text("", "SELECT datetime(mtime,toLocal())"
" FROM event WHERE objid=%d", rid);
isSymbolicCI = (sqlite3_strnicmp(zUuid, zCI, strlen(zCI)) != 0);
isBranchCI = branch_includes_uuid(zCI, zUuid);
Th_StoreUnsafe("current_checkin", zCI);
}else{
zCI = 0;
}
}
if( zCI==0 ){
rNow = db_double(0.0, "SELECT max(mtime) FROM event");
zNow = db_text("", "SELECT datetime(max(mtime),toLocal()) FROM event");
|
| ︙ | ︙ |
Changes to src/doc.c.
| ︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 |
/* The file is now contained in the filebody blob. Deliver the
** file to the user
*/
zMime = nMiss==0 ? P("mimetype") : 0;
if( zMime==0 ){
zMime = mimetype_from_name(zName);
}
| | | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
/* The file is now contained in the filebody blob. Deliver the
** file to the user
*/
zMime = nMiss==0 ? P("mimetype") : 0;
if( zMime==0 ){
zMime = mimetype_from_name(zName);
}
Th_StoreUnsafe("doc_name", zName);
if( vid ){
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
" FROM blob WHERE rid=%d", vid));
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
" WHERE objid=%d AND type='ci'", vid));
}
cgi_check_for_malice();
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
949 950 951 952 953 954 955 |
const char *zComment;
const char *zDate;
const char *zOrigDate;
int okWiki = 0;
Blob wiki_read_links = BLOB_INITIALIZER;
Blob wiki_add_links = BLOB_INITIALIZER;
| | | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
const char *zComment;
const char *zDate;
const char *zOrigDate;
int okWiki = 0;
Blob wiki_read_links = BLOB_INITIALIZER;
Blob wiki_add_links = BLOB_INITIALIZER;
Th_StoreUnsafe("current_checkin", zName);
style_header("Check-in [%S]", zUuid);
login_anonymous_available();
zEUser = db_text(0,
"SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_USER, rid);
zEComment = db_text(0,
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
** Do not overwrite the TH1 variable "default_csp" if it exists, as this
** allows it to be properly overridden via the TH1 setup script (i.e. it
** is evaluated before the header is rendered).
*/
Th_MaybeStore("default_csp", zDfltCsp);
fossil_free(zDfltCsp);
Th_Store("nonce", zNonce);
| > | | | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
** Do not overwrite the TH1 variable "default_csp" if it exists, as this
** allows it to be properly overridden via the TH1 setup script (i.e. it
** is evaluated before the header is rendered).
*/
Th_MaybeStore("default_csp", zDfltCsp);
fossil_free(zDfltCsp);
Th_Store("nonce", zNonce);
Th_StoreUnsafe("project_name",
db_get("project-name","Unnamed Fossil Project"));
Th_StoreUnsafe("project_description", db_get("project-description",""));
if( zTitle ) Th_Store("title", html_lookalike(zTitle,-1));
Th_Store("baseurl", g.zBaseURL);
Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
Th_Store("home", g.zTop);
Th_Store("index_page", db_get("index-page","/home"));
if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
Th_Store("current_page", local_zCurrentPage);
|
| ︙ | ︙ |
Changes to src/th_main.c.
| ︙ | ︙ | |||
2026 2027 2028 2029 2030 2031 2032 |
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
int szVar = zVar ? th_strlen(zVar) : 0;
if( szVar>1 && zVar[0]=='$'
&& Th_GetVar(interp, zVar+1, szVar-1)==TH_OK ){
int nVal;
const char *zVal = Th_GetResult(interp, &nVal);
| | | 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 |
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
int szVar = zVar ? th_strlen(zVar) : 0;
if( szVar>1 && zVar[0]=='$'
&& Th_GetVar(interp, zVar+1, szVar-1)==TH_OK ){
int nVal;
const char *zVal = Th_GetResult(interp, &nVal);
sqlite3_bind_text(pStmt, i, zVal, TH1_LEN(nVal), SQLITE_TRANSIENT);
}
}
while( res==TH_OK && ignore_errors_step(pStmt)==SQLITE_ROW ){
int nCol = sqlite3_column_count(pStmt);
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
int szCol = th_strlen(zCol);
|
| ︙ | ︙ | |||
2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 |
if( zValue ){
if( g.thTrace ){
Th_Trace("set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
}
}
/*
** Appends an element to a TH1 list value. This function is called by the
** transfer subsystem; therefore, it must be very careful to avoid doing
** any unnecessary work. To that end, the TH1 subsystem will not be called
** or initialized if the list pointer is zero (i.e. which will be the case
** when TH1 transfer hooks are disabled).
| > > > > > > > > > > > > > > > > | 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 |
if( zValue ){
if( g.thTrace ){
Th_Trace("set %h {%h}<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
}
}
/*
** Store a string value in a variable in the interpreter
** with the "taint" marking, so that TH1 knows that this
** variable contains content under the control of the remote
** user and presents a risk of XSS or SQL-injection attacks.
*/
void Th_StoreUnsafe(const char *zName, const char *zValue){
Th_FossilInit(TH_INIT_DEFAULT);
if( zValue ){
if( g.thTrace ){
Th_Trace("set %h [taint {%h}]<br>\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, TH1_ADD_TAINT(strlen(zValue)));
}
}
/*
** Appends an element to a TH1 list value. This function is called by the
** transfer subsystem; therefore, it must be very careful to avoid doing
** any unnecessary work. To that end, the TH1 subsystem will not be called
** or initialized if the list pointer is zero (i.e. which will be the case
** when TH1 transfer hooks are disabled).
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 |
/* Finish preliminary processing of tag match queries. */
matchStyle = match_style(zMatchStyle, MS_EXACT);
if( zTagName ){
zType = "ci";
if( matchStyle==MS_EXACT ){
/* For exact maching, inhibit links to the selected tag. */
zThisTag = zTagName;
| | | 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 |
/* Finish preliminary processing of tag match queries. */
matchStyle = match_style(zMatchStyle, MS_EXACT);
if( zTagName ){
zType = "ci";
if( matchStyle==MS_EXACT ){
/* For exact maching, inhibit links to the selected tag. */
zThisTag = zTagName;
Th_StoreUnsafe("current_checkin", zTagName);
}
/* Display a checkbox to enable/disable display of related check-ins. */
if( advancedMenu ){
style_submenu_checkbox("rel", "Related", 0, 0);
}
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
208 209 210 211 212 213 214 |
zVal = "";
}else if( strncmp(zName, "private_", 8)==0 ){
zVal = zRevealed = db_reveal(zVal);
}
if( (j = fieldId(zName))>=0 ){
aField[j].zValue = mprintf("%s", zVal);
}else if( memcmp(zName, "tkt_", 4)==0 && Th_Fetch(zName, &size)==0 ){
| | | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
zVal = "";
}else if( strncmp(zName, "private_", 8)==0 ){
zVal = zRevealed = db_reveal(zVal);
}
if( (j = fieldId(zName))>=0 ){
aField[j].zValue = mprintf("%s", zVal);
}else if( memcmp(zName, "tkt_", 4)==0 && Th_Fetch(zName, &size)==0 ){
Th_StoreUnsafe(zName, zVal);
}
free(zRevealed);
}
Th_Store("tkt_mage", human_readable_age(db_column_double(&q, 2)));
Th_Store("tkt_cage", human_readable_age(db_column_double(&q, 3)));
}
db_finalize(&q);
for(i=0; i<nField; i++){
if( Th_Fetch(aField[i].zName, &size)==0 ){
Th_StoreUnsafe(aField[i].zName, aField[i].zValue);
}
}
}
/*
** Transfer all CGI parameters to variables in the interpreter.
*/
static void initializeVariablesFromCGI(void){
int i;
const char *z;
for(i=0; (z = cgi_parameter_name(i))!=0; i++){
Th_StoreUnsafe(z, P(z));
}
}
/*
** Information about a single J-card
*/
struct jCardInfo {
|
| ︙ | ︙ | |||
1038 1039 1040 1041 1042 1043 1044 |
if( g.zLogin && g.zLogin[0] ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.zLogin);
if( uid ){
char * zEmail =
db_text(0, "SELECT find_emailaddr(info) FROM user WHERE uid=%d",
uid);
if( zEmail ){
| | | | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
if( g.zLogin && g.zLogin[0] ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.zLogin);
if( uid ){
char * zEmail =
db_text(0, "SELECT find_emailaddr(info) FROM user WHERE uid=%d",
uid);
if( zEmail ){
Th_StoreUnsafe("private_contact", zEmail);
fossil_free(zEmail);
}
}
}
Th_StoreUnsafe("login", login_name());
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
(void*)&zNewUuid, 0);
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br>\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
if( P("submitandnew") ){
cgi_redirect(mprintf("%R/tktnew/%s", zNewUuid));
|
| ︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | getAllTicketFields(); initializeVariablesFromCGI(); initializeVariablesFromDb(); if( g.zPath[0]=='d' ) showAllFields(); form_begin(0, "%R/%s", g.zPath); @ <input type="hidden" name="name" value="%s(zName)"> zScript = ticket_editpage_code(); | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 |
getAllTicketFields();
initializeVariablesFromCGI();
initializeVariablesFromDb();
if( g.zPath[0]=='d' ) showAllFields();
form_begin(0, "%R/%s", g.zPath);
@ <input type="hidden" name="name" value="%s(zName)">
zScript = ticket_editpage_code();
Th_StoreUnsafe("login", login_name());
Th_Store("date", db_text(0, "SELECT datetime('now')"));
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br>\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
cgi_redirect(mprintf("%R/tktview/%s", zName));
return;
|
| ︙ | ︙ |