Api Key Exposure in Buffalo with Saml
Api Key Exposure in Buffalo with Saml — how this specific combination creates or exposes the vulnerability
Buffalo is a popular Go web framework often used to build APIs and web applications. When you integrate SAML for authentication in a Buffalo app, improper handling of session state and redirects can inadvertently expose API keys. This typically occurs when API keys are stored in client-side locations (such as JavaScript variables, local storage, or URL query parameters) and the SAML flow does not enforce strict separation between authenticated sessions and key transmission.
During a SAML authentication flow, the Service Provider (SP) — in this case, the Buffalo app — receives a SAML response from the Identity Provider (IdP). If the application embeds API keys into the HTML rendered after login (for example, to initialize a frontend widget or to call a third‑party service from the client), those keys can be read by browser scripts or exposed via Referer headers when the browser makes subsequent requests. Additionally, if Buffalo routes or handlers do not validate the SAML session state correctly, an attacker who can intercept or predict a session ID might reuse a tokenized API key across requests.
The risk is compounded when Buffalo applications use the same session to authorize both UI navigation and backend service calls to external APIs. SAML assertions often contain user attributes but are not intended to carry long‑lived secrets such as API keys. If developers mistakenly treat SAML attributes as a secure mechanism for transporting API keys, the keys become exposed to XSS, CSRF, or referrer leakage. Because SAML relies on redirects and signed assertions, missing validation of the AuthnRequest or improper logout handling can leave stale sessions that still hold references to sensitive keys on the client side.
middleBrick scans identify this class of exposure by checking whether API keys appear in responses delivered to unauthenticated or low‑privilege contexts, and whether SAML‑related redirects leak sensitive data in URLs or Referer headers. The scanner does not assume the framework’s internal architecture; it observes the runtime behavior of the endpoint, flagging findings such as API keys in JavaScript blocks, overly broad CORS rules, or missing integrity checks on SAML‑initiated flows.
For example, a Buffalo handler that returns an HTML page containing a hardcoded API key after a SAML login could be flagged as high severity for Data Exposure. Even if the SAML flow itself is correctly signed, the placement of the key in the rendered page creates a client‑side exposure path that an attacker can exploit via XSS or simple script inspection.
Saml-Specific Remediation in Buffalo — concrete code fixes
Remediation focuses on ensuring API keys never travel in the SAML flow or in responses to browsers, and that Buffalo sessions are tightly scoped and invalidated appropriately. Keep API keys on the server, use short‑lived tokens for external calls, and avoid echoing SAML attributes into client‑side JavaScript.
1. Store API keys securely on the server. Do not embed them in HTML or JavaScript. Use environment variables or a secrets store, and reference them only from server‑side code.
2. Ensure SAML responses are consumed and validated strictly. Verify the InResponseTo field, the destination URL, and the signature. Do not use SAML attributes to pass API keys.
3. After logout, invalidate server sessions and clear any cached tokens.
Below are concrete code examples for a Buffalo app that integrates SAML with secure handling of external API calls.
Buffalo SAML setup (server side)
package actions
import (
"github.com/gobuffalo/buffalo"
"github.com/gobuffalo/packr/v2"
"github.com/crewjam/saml"
"github.com/crewjam/saml/samlsp"
"net/http"
"os"
)
var (
samlSP *samlsp.SAMLSP
apiKey = os.Getenv("EXTERNAL_API_KEY") // stored server‑side, not in the client
)
func initSAML() (*samlsp.SAMLSP, error) {
box := packr.New("saml", "../../saml")
idpCert, err := box.GetBytes("idp.crt")
if err != nil {
return nil, err
}
spKey, err := box.GetBytes("sp.key")
if err != nil {
return nil, err
}
spCert, err := box.GetBytes("sp.crt")
if err != nil {
return nil, err
}
idpMetadata := &saml.EntityDescriptor{}
if err := idpMetadata.ReadFromCert(idpCert); err != nil {
return nil, err
}
samlSP, err = samlsp.New(samlsp.Options{
IDPMetadata: idpMetadata,
Key: spKey,
Certificate: spCert,
AllowUnencryptedAuthnRequests: false,
RequireAuthnRequestsSigned: true,
})
return samlSP, err
}
func LoginHandler(c buffalo.Context) error {
http.Redirect(c.Response(), c.Request(), samlSP.SSOUrl(&saml.SSOOptions{ReturnTo: c.Request().URL.String()}), http.StatusFound)
return nil
}
func ACSHandler(c buffalo.Context) error {
// SAML response is validated by the samlSP middleware; session is established server‑side
session, ok := samlSP.Session(c.Request())
if !ok {
return c.Render(401, r.String("Unauthorized"))
}
// Use session.NameID for logging or local user lookup; do not place API keys in claims
c.Session().Set("nameid", session.NameID)
// Server‑side call to external API using the securely stored apiKey
client := &http.Client{}
req, _ := http.NewRequest("GET", "https://external.example.com/data", nil)
req.Header.Set("Authorization", "Bearer "+apiKey) // apiKey never reaches the browser
resp, err := client.Do(req)
if err != nil {
return c.Error(500, err)
}
defer resp.Body.Close()
// Render a safe response without exposing keys
return c.Render(200, r.JSON(map[string]string{"status": "ok"}))
}
4. Avoid exposing SAML attributes in JavaScript. If you need user information on the client, provide a minimal, safe endpoint that returns only what is necessary, and ensure the browser does not include API keys in Referer or query strings.
5. Configure CORS strictly and use CSRF protection. Do not allow origins that can read SAML‑initiated responses if they are not trusted.
These steps ensure that API keys remain server‑side and that SAML is used strictly for authentication, not for transporting secrets. middleBrick can verify that API keys are not present in responses and that SAML flows include required signing and validation checks.