Fossil Forum

anonymous 2 weeks, 6 days ago

Post: How to safely use current_checkin in TH1

Hello:

My skin has the following code in the header:

if {[anoncap oh]} {
  if {![info exists current_checkin]} {set current_checkin tip}
  menulink "/dir?ci=$current_checkin" Files {}
}

The idea is that the Files link in the header will always take the user to the files associated with the currently displayed commit. For example if I am viewing a commit using .../info/bc539c062e7d0cd5, clicking on the Files link will take me to .../dir?ci=bc539c062e7d0cd5.

However I keep getting the error:

TH1 XSS vulnerability due to tainted output string: "<a href='/.../dir?ci=bc539c062e7d0cd5' class='active '>Files</a>
" (pid 1886)
while in /dir

I finally managed to track it down to the current_checkin variable. (Side note: including the name of the variable that is tainted would be very helpful. IIRC I was still getting the error when it was set to tip which was confusing but understandable when I looked at the code.)

I can get rid of the error if I use:

if {[anoncap oh]} {
  if {![info exists current_checkin]} {set current_checkin tip}
  menulink "/dir?ci=[httpize $current_checkin]" Files {}
}

Is this the correct fix?

Also my skin is based on an older version of the Eagle skin and I noticed that menulink isn't used in any of the skins anymore.

The only reference to it is in www/forum.wiki. I assume it was removed in preference to the mainmenu setting. But the mainmenu is static and doesn't allow customizing the links according to the current page context (i.e. current_checkin). I don't know of any way in TH1 (or TCL) to do the equivalent of the shells: ${current_checkin:-tip} and even if I did I would not be able to untaint it.

Thanks.

stephan 2 weeks, 6 days ago

But the mainmenu is static and doesn't allow customizing the links according to the current page context (i.e. current_checkin).

This does not answer your question (which i don't have an answer for), but mainmenu is not quite static: it's a th1 list. You can manipulate it as much as you like before rendering it (which each skin does separately):

[stephan@nuc:~/f/fossil/skins]$ grep -w mainmenu */head*.txt
ardoise/header.txt:    <nav class="mainmenu" title="Main Menu">
ardoise/header.txt:          foreach {name url expr class} $mainmenu {
black_and_white/header.txt:<nav class="mainmenu" title="Main Menu">
black_and_white/header.txt:    foreach {name url expr class} $mainmenu {
blitz/header.txt:    <nav class="mainmenu" title="Main Menu">
blitz/header.txt:          foreach {name url expr class} $mainmenu {
darkmode/header.txt:<nav class="mainmenu" title="Main Menu">
darkmode/header.txt:    foreach {name url expr class} $mainmenu {
default/header.txt:<nav class="mainmenu" title="Main Menu">
default/header.txt:    foreach {name url expr class} $mainmenu {
eagle/header.txt:<nav class="mainmenu" title="Main Menu">
eagle/header.txt:    foreach {name url expr class} $mainmenu {
etienne/header.txt:<nav class="mainmenu" title="Main Menu">
etienne/header.txt:    foreach {name url expr class} $mainmenu {
khaki/header.txt:<nav class="mainmenu" title="Main Menu">
khaki/header.txt:    foreach {name url expr class} $mainmenu {
original/header.txt:<nav class="mainmenu" title="Main Menu">
original/header.txt:    foreach {name url expr class} $mainmenu {
plain_gray/header.txt:<nav class="mainmenu" title="Main Menu">
plain_gray/header.txt:    foreach {name url expr class} $mainmenu {
xekri/header.txt:<nav class="mainmenu" title="Main Menu">
xekri/header.txt:    foreach {name url expr class} $mainmenu {
anonymous 2 weeks, 6 days ago

Hi Stephen:

But the mainmenu is static and doesn't allow customizing the links according to the current page context

This does not answer your question (which i don't have an answer for), but mainmenu is not quite static: it's a th1 list. You can manipulate it as much as you like before rendering it

I guess I should have said the elements in the mainmenu list are static. I can't really manipulate it but I can create a new mainmenu list with a different URL for the File link.

TH1 only supports lappend for changing a list. TCL has lreplace or lset that can be used with lsearch to replace the url parameter by searching $mainmenu for File then using lset/lreplace on the returned lsearch index + 1.

The following script creates an lset proc and uses it to replace the url. The lset only accepts one index and not an index list (like TCL's lset) to handle nested list structures.

proc lset {listName index replacement} {
    upvar 1 $listName theList
    set current_index 0
    set newmenu {}
    foreach item $theList {
    if {$current_index == $index} {
        lappend newmenu $replacement
    } else {
        lappend newmenu $item
    }
    set current_index [expr $current_index+1]
    }
    return $newmenu
}


set mainmenu {Home      /home        *              {}
Timeline  /timeline    {o r j}        {}
Files     /dir?ci=tip  oh             desktoponly
Branches  /brlist      o              wideonly
Tags      /taglist     o              wideonly
Forum     /forum       {@2 3 4 5 6}   wideonly
Chat      /chat        C              wideonly
Tickets   /ticket      r              wideonly
Wiki      /wiki        j              wideonly
Admin     /setup       {a s}          desktoponly
Logout    /logout      L              wideonly
Login     /login       !L             wideonly}

# print starting case
# Its formatting is much better then the list
# I construct. Not sure why.
puts "$mainmenu\n"

# Find the Timeline
puts "\n[lindex $mainmenu 4]\n\n"

# find the File entry
set file_loc [lsearch $mainmenu "Files"]

if {[expr "$file_loc % 4"] != 0} {
    error "ERROR: label found in the wrong position"
    # not sure how I can use lsearch to find the next match
    # in the list past the one that was returned. TCL's -start
    # or -all flags don't seem to be supported.
}

# do the switch
set mainmenu [lset mainmenu [expr $file_loc+1] "/dir?ci=deadbeef"]

# print post switch case.
# without [list ...] puts doesn't put {}'s around lists printing
# "{a s}" as "a s". I need to use foreach to insert line breaks.
foreach {name url perm when} $mainmenu {
    puts "[list $name $url $perm $when]\n"
}

# make sure the Timeline is at the same location.
puts "\n[lindex $mainmenu 4]"
puts ""

producing:

Home      /home        *              {}
Timeline  /timeline    {o r j}        {}
Files     /dir?ci=tip  oh             desktoponly
Branches  /brlist      o              wideonly
Tags      /taglist     o              wideonly
Forum     /forum       {@2 3 4 5 6}   wideonly
Chat      /chat        C              wideonly
Tickets   /ticket      r              wideonly
Wiki      /wiki        j              wideonly
Admin     /setup       {a s}          desktoponly
Logout    /logout      L              wideonly
Login     /login       !L             wideonly

Timeline

Home /home * {}
Timeline /timeline {o r j} {}
Files /dir?ci=deadbeef oh desktoponly
Branches /brlist o wideonly
Tags /taglist o wideonly
Forum /forum {@2 3 4 5 6} wideonly
Chat /chat C wideonly
Tickets /ticket r wideonly
Wiki /wiki j wideonly
Admin /setup {a s} desktoponly
Logout /logout L wideonly
Login /login !L wideonly

Timeline
stephan 2 weeks, 6 days ago

TH1 only supports lappend for changing a list. ...

True, you're very limited in the list operations1, But you could add a placeholder entry such as:

BLAH x oh {}

Pass all other entries through as-is and replace the 2nd element of that one with /dir?ci=....

Not that i'm recommending that - th1 is pretty limited, so there may well be some frustration or dead-end limitations involved.

Fossil has a rarely-used build-time configuration flag, --with-tcl, which enables th1 to embed tcl code, but my experience with that option is 0 so i won't do more than point it out as a possibility for custom fossil builds.

That still doesn't(?) solve the taint problem, though, for which i've got no recommendations (for lack of know-how regarding that recently-added capability).


  1. patches to widen the set of operations would be thoughtfully considered! 

anonymous 2 weeks, 5 days ago

Fossil has a rarely-used build-time configuration flag, --with-tcl, which enables th1 to embed tcl code, but my experience with that option is 0 so i won't do more than point it out as a possibility for custom fossil builds.

I build --with-tcl on all my systems. However I can't count on a user who clones the repo having a tcl enabled fossil build, hence limiting my solution to TH1.

I put a real entry for the BLAH url as a fallback. If somebody updates the mainmenu list and changes BLAH at least they will have the URL setting they expect. Only if BLAH is "Files" (not "files", "directory" etc...) will my example change it to the checkin specific link. This way they can reorder the main menu and still have it work.

florian.balmer 2 weeks, 4 days ago

httpize -- Is this the correct fix?

Probably, yes. I've come across this when updating the Custom Skins document with information about tainted strings.

I've now also added the current_checkin variable to the docs, and from the source code it's clear that it's derived from query parameters and therefore unsafe (or "tainted").

Keyboard Shortcuts

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