Skip to main content
Glama

role_escalation_test

Test for privilege escalation vulnerabilities by sending requests with manipulated role cookies and JSON body fields to identify unauthorized access opportunities.

Instructions

Test cookie/parameter-based role escalation.

Sends requests with various role cookie values (Admin=true, roleid=2, etc.) and checks for privilege escalation. Also tests JSON body field manipulation for profile update endpoints.

Returns: {"baseline": dict, "results": [{"value": str, "status": int, "length": int, "escalated": bool}], "escalation_candidates": [str]}.

Side effects: If json_body is set, sends POST/PUT requests that may modify state.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesProtected URL to access, e.g. https://target/admin or https://target/api/users
cookie_nameYesCookie name for role control, e.g. 'admin', 'role', 'is_admin'
cookie_valuesYesValues to test, e.g. ['true','1','admin','2','yes']
extra_cookiesNoAdditional cookies to include, e.g. 'session=abc123; logged_in=true'
json_bodyNoJSON body for POST-based role escalation, e.g. '{"roleid":2}'. Will test each value substituted
json_fieldNoJSON field to manipulate in json_body, e.g. 'roleid'

Implementation Reference

  • The tool `role_escalation_test` is registered and implemented here. It takes a URL, cookie name, and various values, then performs curl requests with different cookies to test for privilege escalation based on HTTP status code changes or response length discrepancies.
    server.tool(
      "role_escalation_test",
      "Test cookie/parameter-based role escalation.\n\nSends requests with various role cookie values (Admin=true, roleid=2, etc.) and checks for privilege escalation. Also tests JSON body field manipulation for profile update endpoints.\n\nReturns: {\"baseline\": dict, \"results\": [{\"value\": str, \"status\": int, \"length\": int, \"escalated\": bool}], \"escalation_candidates\": [str]}.\n\nSide effects: If json_body is set, sends POST/PUT requests that may modify state.",
      {
        url: z
          .string()
          .describe(
            "Protected URL to access, e.g. https://target/admin or https://target/api/users"
          ),
        cookie_name: z
          .string()
          .describe(
            "Cookie name for role control, e.g. 'admin', 'role', 'is_admin'"
          ),
        cookie_values: z
          .array(z.string())
          .min(1)
          .max(20)
          .describe(
            "Values to test, e.g. ['true','1','admin','2','yes']"
          ),
        extra_cookies: z
          .string()
          .optional()
          .describe(
            "Additional cookies to include, e.g. 'session=abc123; logged_in=true'"
          ),
        json_body: z
          .string()
          .optional()
          .describe(
            "JSON body for POST-based role escalation, e.g. '{\"roleid\":2}'. Will test each value substituted"
          ),
        json_field: z
          .string()
          .optional()
          .describe(
            "JSON field to manipulate in json_body, e.g. 'roleid'"
          ),
      },
      async ({
        url,
        cookie_name,
        cookie_values,
        extra_cookies,
        json_body,
        json_field,
      }) => {
        requireTool("curl");
    
        // Baseline without the role cookie
        const baselineArgs = [
          "-sk",
          "-o",
          "-",
          "-w",
          "\n__META__%{http_code}:%{size_download}",
        ];
        if (extra_cookies) {
          baselineArgs.push("-b", extra_cookies);
        }
        baselineArgs.push(url);
    
        const baselineRes = await runCmd("curl", baselineArgs);
        let baseBody = baselineRes.stdout;
        const baseMetaMarker = baseBody.lastIndexOf("__META__");
        let baseStatus = 0;
        let baseLength = 0;
        if (baseMetaMarker !== -1) {
          const meta = baseBody.slice(baseMetaMarker + 8).trim();
          const parts = meta.split(":");
          baseStatus = parts[0] ? parseInt(parts[0], 10) : 0;
          baseLength = parts[1] ? parseInt(parts[1], 10) : 0;
        }
    
        const results: Array<{
          cookie_value: string;
          status: number;
          length: number;
          escalated: boolean;
          response_snippet: string;
        }> = [];
        const escalationCandidates: string[] = [];
    
        for (const value of cookie_values) {
          let cookieStr = `${cookie_name}=${value}`;
          if (extra_cookies) {
            cookieStr = `${extra_cookies}; ${cookieStr}`;
          }
    
          let curlArgs: string[];
          if (json_body && json_field) {
            // POST/PUT with modified JSON body
            let modifiedBody = json_body;
            try {
              const bodyDict = JSON.parse(json_body);
              bodyDict[json_field] = value;
              modifiedBody = JSON.stringify(bodyDict);
            } catch {
              modifiedBody = json_body;
            }
    
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}",
              "-X",
              "POST",
              "-H",
              "Content-Type: application/json",
              "-d",
              modifiedBody,
              "-b",
              cookieStr,
              url,
            ];
          } else {
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}",
              "-b",
              cookieStr,
              url,
            ];
          }
    
          const res = await runCmd("curl", curlArgs);
          let resBody = res.stdout;
          const metaMarker = resBody.lastIndexOf("__META__");
          let status = 0;
          let length = 0;
          if (metaMarker !== -1) {
            const meta = resBody.slice(metaMarker + 8).trim();
            const parts = meta.split(":");
            status = parts[0] ? parseInt(parts[0], 10) : 0;
            length = parts[1] ? parseInt(parts[1], 10) : 0;
            resBody = resBody.slice(0, metaMarker);
          }
    
          const escalated =
            (status === 200 && [401, 403, 302].includes(baseStatus)) ||
            (Math.abs(length - baseLength) > 100 && status === 200);
    
          const entry = {
            cookie_value: value,
            status,
            length,
            escalated,
            response_snippet: resBody.slice(0, 500),
          };
          results.push(entry);
          if (escalated) {
            escalationCandidates.push(value);
          }
        }
    
        const result = {
          baseline: { status: baseStatus, length: baseLength },
          cookie_name,
          results,
          escalation_candidates: escalationCandidates,
          hint:
            escalationCandidates.length > 0
              ? `Role escalation possible with ${cookie_name}=${JSON.stringify(escalationCandidates)}`
              : "No escalation detected. Try different cookie names or values.",
        };
    
        return { content: [{ type: "text", text: JSON.stringify(result) }] };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/operantlabs/operant-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server