HIGH cors wildcardactixhmac signatures

Cors Wildcard in Actix with Hmac Signatures

Cors Wildcard in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability

A CORS wildcard (Access-Control-Allow-Origin: *) combined with Hmac Signatures in Actix can unintentionally expose authenticated or sensitive endpoints to any origin. When an endpoint uses Hmac Signatures for request authentication (typically via a signature in a header such as x-api-signature), developers may assume that because the signature is required, any origin can safely make requests. However, a wildcard CORS policy allows browsers to send cross-origin requests for simple methods and headers, and with credentialed requests or custom headers, preflight responses will reflect the wildcard back to the attacker’s page.

Consider an Actix web service that validates an Hmac signature derived from a shared secret and request metadata. If the CORS configuration sets Access-Control-Allow-Origin: * and also exposes headers like x-api-signature or returns Access-Control-Allow-Credentials: true while using a wildcard, a malicious site can craft requests that the browser will process, including the necessary signature headers injected via JavaScript. Although the server verifies the Hmac, the browser’s same-origin policy relaxation means an unauthorized webpage can probe or interact with the endpoint, leading to unauthorized actions or information leakage if the endpoint has side effects.

This combination is particularly dangerous when the Hmac does not include a per-origin or per-client binding. An attacker can use fetch from a compromised frontend to call the endpoint, relying on the browser to handle CORS and headers. Because the CORS response exposes the effective endpoint behavior to the attacker’s origin, they can enumerate valid inputs, observe timing differences, or infer business logic, even if each request must carry a valid Hmac. In secure designs, CORS origins should be explicit and limited to trusted frontends, and sensitive endpoints should avoid wildcard origins regardless of signature requirements.

The risk is compounded if the Actix service also relies on simple secret-based Hmac without additional context binding (e.g., timestamp or nonce), because a leaked signature can be reused from the attacker’s origin if CORS permits it. Proper server-side checks must validate the Origin header against an allowlist and ensure that CORS responses do not reflect wildcards when credentials or custom headers are involved. MiddleBrick’s scans detect such misconfigurations by correlating CORS headers with authentication schemes and API contract analysis, including OpenAPI/Swagger spec references and runtime behavior.

In practice, this means an Actix route that uses Hmac Signatures and sets CORS headers programmatically must not apply a wildcard. Instead, configure CORS with precise origins and selectively expose only safe headers. For example, returning Access-Control-Allow-Origin based on the request origin after validation, while keeping Access-Control-Allow-Credentials true only for known origins, prevents the browser from making unauthorized cross-origin calls even when Hmac headers are present.

Hmac Signatures-Specific Remediation in Actix — concrete code fixes

To remediate CORS misconfigurations when using Hmac Signatures in Actix, tighten CORS settings and ensure Hmac validation includes contextual binding. Below are concrete, syntactically correct examples that you can adapt in an Actix web application.

1. Configure strict CORS without wildcards

Instead of using a wildcard, explicitly allow known frontend origins and selectively expose headers. Here is an Actix CORS configuration that avoids * and sets safe exposed headers:

use actix_cors::Cors; use actix_web::middleware::Logger; use actix_web::{web, App, HttpServer, HttpResponse, Responder};

fn cors_config() -> Cors { let allowed_origin = "https://app.example.com".parse().unwrap(); Cors::default() .allowed_origin(&allowed_origin) .allowed_methods(vec!["GET", "POST"]) .allowed_headers(vec!["accept", "x-api-signature", "content-type"]) .exposed_headers(vec!["x-request-id"]) .max_age(3600) .supports_credentials() }

This configuration ensures that only https://app.example.com can make cross-origin requests, and only specified headers are exposed to the browser. The supports_credentials option allows cookies or authorization headers to be included, but only for the allowed origin.

2. Validate Hmac with origin binding

Enhance Hmac validation by incorporating the request origin and a nonce or timestamp. This prevents replay across origins even if a signature is intercepted. The following example shows a handler that extracts and verifies an Hmac signature, including an origin check:

use actix_web::{post, web, HttpResponse, Result}; use hmac::{Hmac, Mac}; use sha2::Sha256; type HmacSha256 = Hmac<Sha256>;

#[post("/secure")] async fn secure_endpoint(
    req: web::Json<serde_json::Value>,
    headers: actix_web::HttpRequest,
) -> Result<impl Responder> { let signature = headers.get("x-api-signature").ok_or_else(|| HttpResponse::BadRequest().finish())?; let origin = headers.origin().map(|o| o.as_str()).unwrap_or(""); // Strict origin allowlist if origin != "https://app.example.com" { return Err(HttpResponse::Forbidden().finish()); } // Recompute expected signature with origin and nonce let body = req.body(); let nonce = headers.get("x-nonce").ok_or_else(|| HttpResponse::BadRequest().finish())?; let mut mac = HmacSha256::new_from_slice(b"super-secret-key").map_err(|_| HttpResponse::InternalServerError().finish())?; mac.update(origin.as_bytes()); mac.update(nonce.as_bytes()); mac.update(body); let computed = mac.finalize(); // Constant-time comparison if computed.verify(signature.as_bytes()).is_err() { return Err(HttpResponse::Unauthorized().finish()); } Ok(HttpResponse::Ok().json(serde_json::json!({ "status": "ok" }))) }

This code verifies the Hmac while binding the computation to the request origin and a nonce header. If the origin does not match the allowlist, the request is rejected before Hmac verification, mitigating cross-origin abuse even when CORS is permissive for other endpoints.

3. Centralize CORS and Hmac validation in middleware

For larger services, implement a custom Actix middleware that checks both CORS and Hmac consistently across routes. This avoids accidental per-route misconfigurations:

use actix_web::{dev::{Service, ServiceRequest, ServiceResponse, Transform}, Error, HttpMessage}; use actix_web::http::header::HeaderValue; use std::future::{ready, Ready}; use std::rc::Rc;

pub struct SecureCorsHmac { origin: String, secret: Vec<u8>, } impl SecureCorsHmac { pub fn new(origin: String, secret: Vec<u8>) -> Self { Self { origin, secret } } }

trait Identity: Sized { fn id(&self) -> String; }

impl Transform<S, ServiceRequest> for SecureCorsHmac where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static, S::Future: 'static, { type Response = ServiceResponse<B>; type Error = Error; type InitError = (); type Transform = SecureCorsHmacMiddleware<S>; type Future = Ready<Result<Self::Transform, Self::InitError>>;

fn new_transform(&self, service: S) -> Self::Future { ready(Ok(SecureCorsHmacMiddleware { service: Rc::new(service), origin: self.origin.clone(), secret: self.secret.clone() })) } }

struct SecureCorsHmacMiddleware<S> { service: Rc<S>, origin: String, secret: Vec<u8>, } impl<S, B> Service<ServiceRequest> for SecureCorsHmacMiddleware<S> where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, { type Response = ServiceResponse<B>; type Error = Error; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>;

fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.service.poll_ready(cx) }

fn call(&self, req: ServiceRequest) -> Self::Future { let origin = req.headers().get("origin").and_then(|v| v.to_str().ok()).unwrap_or(""); if origin != self.origin { let fut = async { Err(Error::from(HttpResponse::Forbidden().finish())) }; return Box::pin(fut); } // Verify Hmac in a cloned request let req2 = req.clone(); let secret = self.secret.clone(); let fut = async move { let signature = req2.headers().get("x-api-signature").ok_or_else(|| Error::from(HttpResponse::BadRequest().finish()))?; let mut mac = HmacSha256::new_from_slice(&secret).map_err(|_| Error::from(HttpResponse::InternalServerError().finish()))?; mac.update(origin.as_bytes()); mac.update(req2.headers().get("x-nonce").map(|v| v.as_bytes()).unwrap_or_default()); // body omitted for brevity; in practice, use payload to compute // constant-time verify if mac.verify(signature.as_bytes()).is_err() { return Err(Error::from(HttpResponse::Unauthorized().finish())); } let res = self.service.call(req2).await?; Ok(res) }; Box::pin(fut) } }

With these fixes, the Actix service rejects cross-origin requests unless the origin is explicitly trusted, and each Hmac is bound to the origin and a nonce, reducing the impact of leaked signatures and eliminating risks from a wildcard CORS policy.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Why is a CORS wildcard dangerous when Hmac Signatures are used in Actix?
A wildcard allows any origin to make requests; browsers may send cross-origin calls that include required Hmac headers. Even with Hmac validation, an attacker’s page can trigger requests via JavaScript, enabling unauthorized actions or information leakage if the Hmac lacks origin binding.
How can I safely expose headers like x-api-signature while using CORS in Actix?
Do not use a wildcard. Use explicit allowed origins, set Access-Control-Allow-Origin to a specific trusted origin, and expose only necessary headers. Bind Hmac validation to the request origin and include a nonce or timestamp to prevent replay across origins.