How API Security Works in AUTOMATIC1111: Authentication and Request Validation

AUTOMATIC1111 secures its FastAPI-based REST API through optional HTTP Basic Authentication configured via --api-auth and request validation that filters sensitive parameters and blocks local network requests using runtime flags.

The AUTOMATIC1111/stable-diffusion-webui repository exposes a REST API at /sdapi/v1/... for programmatic access to Stable Diffusion generation features. Understanding how API security works in AUTOMATIC1111 is essential before exposing the service to networks beyond localhost, as the implementation combines credential-based access control with strict input sanitization to prevent unauthorized usage and server-side request forgery (SSRF).

Authentication Layer

The WebUI implements HTTP Basic Authentication as an optional but recommended security boundary. When enabled, every API endpoint requires valid credentials passed in the Authorization header, with passwords validated using constant-time comparison to prevent timing attacks.

Enabling HTTP Basic Authentication

Authentication is configured at startup using command-line arguments defined in modules/cmd_args.py. You can pass credentials directly or load them from a file:


# Single user

python webui.py --api-auth username:password

# Multiple users

python webui.py --api-auth user1:pass1,user2:pass2

# From file

python webui.py --api-auth-path /path/to/credentials.txt

In modules/api/api.py, the Api class constructor parses these credentials into a dictionary during initialization:

if shared.cmd_opts.api_auth:
    for auth in shared.cmd_opts.api_auth.split(","):
        user, password = auth.split(":")
        self.credentials[user] = password

The Authentication Flow

When --api-auth is present, the add_api_route method registers every endpoint with a FastAPI dependency on self.auth:

if shared.cmd_opts.api_auth:
    return self.app.add_api_route(path, endpoint,
                                 dependencies=[Depends(self.auth)], **kwargs)

The auth method itself, implemented in modules/api/api.py, uses FastAPI's HTTPBasic scheme and secrets.compare_digest for secure comparison:

def auth(self, credentials: HTTPBasicCredentials = Depends(HTTPBasic())):
    if credentials.username in self.credentials:
        if secrets.compare_digest(credentials.password, 
                                  self.credentials[credentials.username]):
            return True
    raise HTTPException(
        status_code=401, 
        detail="Incorrect username or password",
        headers={"WWW-Authenticate": "Basic"}
    )

If no --api-auth flag is provided, the API operates in open mode, suitable only for trusted local networks.

Request Validation and Input Sanitization

Beyond authentication, the API validates incoming payloads to prevent parameter injection and restricts external HTTP requests to mitigate SSRF vulnerabilities.

Pydantic Model Whitelisting

The API dynamically generates Pydantic models from internal processing classes (StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img) but explicitly excludes dangerous fields. In modules/api/models.py, the API_NOT_ALLOWED list defines prohibited parameters:

API_NOT_ALLOWED = [
    "self", "kwargs", "sd_model", "outpath_samples", "outpath_grids",
    "sampler_index", "extra_generation_params", "overlay_images",
    "do_not_reload_embeddings", "seed_enable_extras", "prompt_for_display",
    "sampler_noise_scheduler_override", "ddim_discretize"
]

During model generation, the PydanticModelGenerator skips these fields, ensuring API consumers cannot override internal file paths, change model storage locations, or access restricted generation parameters.

Image URL Validation and SSRF Protection

When processing base64-encoded images or remote URLs in modules/api/api.py, the decode_base64_to_image function implements two critical runtime checks stored in the global opts object (modules/shared.py):

  • opts.api_enable_requests: Master switch for all external HTTP GET requests (default True)
  • opts.api_forbid_local_requests: Blocks requests to private IP ranges when True (default True)

The validation logic resolves hostnames and rejects non-global addresses:

def decode_base64_to_image(encoding):
    if encoding.startswith("http://") or encoding.startswith("https://"):
        if not opts.api_enable_requests:
            raise HTTPException(500, "Requests not allowed")
        if opts.api_forbid_local_requests and not verify_url(encoding):
            raise HTTPException(500, "Request to local resource not allowed")
        # ... proceed with request

The verify_url helper ensures every resolved IP is global (not private, loopback, or link-local), preventing attackers from using the API to probe internal network services.

Security Configuration Options

All security parameters are configurable via CLI flags at startup:

Flag Purpose Default
--api-auth Sets username:password pairs for Basic Auth None (open)
--api-auth-path Loads credentials from a file None
--api-enable-requests Allows external HTTP requests for images True
--api-forbid-local-requests Blocks requests to local/private IPs True

These values persist in shared.opts and are accessible throughout the application lifecycle.

Practical Implementation Examples

Authenticated Text-to-Image Request

Call the txt2img endpoint with Basic Auth credentials:

curl -X POST "http://127.0.0.1:7860/sdapi/v1/txt2img" \
     -u alice:SecretPass \
     -H "Content-Type: application/json" \
     -d '{
           "prompt": "a cyberpunk city at sunset",
           "steps": 30,
           "cfg_scale": 7,
           "width": 512,
           "height": 512,
           "sampler_index": "Euler",
           "send_images": true
         }' | jq .

The -u flag generates the Authorization: Basic header that the auth method validates against the credentials supplied via --api-auth.

Submitting Remote Images with URL Validation

For img2img operations using external images:

curl -X POST "http://127.0.0.1:7860/sdapi/v1/img2img" \
     -u admin:Pass123 \
     -H "Content-Type: application/json" \
     -d '{
           "init_images": ["https://example.com/public/photo.jpg"],
           "prompt": "portrait in the style of Van Gogh",
           "denoising_strength": 0.6,
           "steps": 20
         }' | jq .

Under the hood, decode_base64_to_image checks opts.api_enable_requests and opts.api_forbid_local_requests, then calls verify_url to ensure example.com resolves to a global IP address before fetching the resource.

Hardening Against External Requests

To completely disable remote image fetching and prevent SSRF attacks:

python webui.py --api-auth admin:StrongPwd \
                --api-enable-requests=False \
                --api-forbid-local-requests=True

Any request containing an external URL now returns:

{
  "error": "HTTPException",
  "detail": "Requests not allowed"
}

Summary

  • Authentication is opt-in: Use --api-auth to enable HTTP Basic Authentication via modules/api/api.py, storing credentials in self.credentials and validating with secrets.compare_digest.
  • Parameter filtering is automatic: The API_NOT_ALLOWED whitelist in modules/api/models.py prevents API consumers from setting internal paths or restricted generation parameters.
  • SSRF protection is runtime-configurable: The decode_base64_to_image function in modules/api/api.py uses verify_url and opts.api_forbid_local_requests to block requests to local network resources.
  • Security flags are centralized: All settings are defined in modules/cmd_args.py and stored in modules/shared.py's global opts object.

Frequently Asked Questions

Is the AUTOMATIC1111 API open by default?

Yes. Unless you explicitly provide the --api-auth command-line argument, the REST API endpoints in modules/api/api.py do not require authentication, making them accessible to any client that can reach the server. You should only run without authentication on trusted local networks.

How does the API prevent server-side request forgery (SSRF)?

The decode_base64_to_image function checks opts.api_forbid_local_requests (default True) and calls verify_url to resolve hostnames and validate that target IPs are global addresses. Requests to private ranges (10.0.0.0/8, 192.168.0.0/16), loopback (127.0.0.1), or link-local addresses are rejected with a 500 error before any HTTP request is executed.

Which internal parameters are blocked from API access?

The API_NOT_ALLOWED list in modules/api/models.py excludes sensitive fields such as sd_model, outpath_samples, outpath_grids, sampler_index, and sampler_noise_scheduler_override from the dynamically generated Pydantic models. This prevents API users from changing model storage paths or overriding internal generation settings.

Can I load authentication credentials from a file instead of the command line?

Yes. Use the --api-auth-path flag to specify a text file containing username:password pairs. The startup logic in modules/api/api.py reads this file and populates self.credentials identically to the --api-auth flag, keeping sensitive credentials out of process lists and shell history.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →