Api Key Exposure in Spring Boot with Mongodb
Api Key Exposure in Spring Boot with Mongodb — how this specific combination creates or exposes the vulnerability
When a Spring Boot application stores or uses API keys with a MongoDB backend, the risk of exposure typically arises from insecure handling of sensitive values rather than MongoDB itself. MongoDB stores data as BSON documents and does not inherently expose keys, but application-side practices determine whether keys are protected at rest and in use.
One common pattern is storing API keys directly in MongoDB collections, for example in a services or credentials collection. If these fields are not encrypted before being written, an authenticated database user or an attacker who gains access to the database can read the keys. A typical vulnerable document might look like { "_id": ObjectId("..."), "name": "payment-service", "apiKey": "sk_live_abc123" }.
Spring Boot applications often inject configuration via environment variables or property files, but mistakes happen. Developers might accidentally log the full configuration object, including the key, or include it in error responses. In a MongoDB context, this can happen if a service fetches a document and serializes it into logs or stack traces. For example, a controller that returns the document as-is can expose the key in HTTP responses when an error occurs.
Another exposure vector is the connection string. Spring Boot applications typically store the MongoDB URI in application.properties or application.yml. If this file is committed to a shared repository or exposed through a misconfigured artifact repository, the URI along with any embedded credentials can be leaked. A URI like mongodb://apiKey:superSecretKey@mongodb.example.com:27017/app embeds the key in plaintext and can be discovered through source code leaks or server misconfigurations.
Insecure deserialization or improper data mapping can also lead to exposure. If a Spring Boot application maps incoming JSON directly to MongoDB documents without validation, an attacker might inject or exfiltrate keys via crafted payloads. For instance, an endpoint that accepts a filter object and directly builds a MongoDB query could be abused to retrieve documents containing keys if proper access controls are missing.
Finally, insufficient runtime protections amplify the impact. Without field-level encryption or strict access controls, a compromised application user or an over-privileged database role can read sensitive fields. This is especially risky in shared environments where multiple services or tenants share a cluster. The combination of a permissive MongoDB deployment and a Spring Boot app that treats keys as regular data increases the likelihood of accidental or intentional disclosure.
Mongodb-Specific Remediation in Spring Boot — concrete code fixes
To reduce the risk of API key exposure, treat keys as sensitive data that must be protected both in transit and at rest. Use encryption before storing in MongoDB and avoid embedding keys in connection strings.
1. Use encrypted fields instead of raw keys
Encrypt API keys in the application before persisting them. With Spring Data MongoDB, you can leverage a custom converter to encrypt and decrypt values. Below is a concise example using AES-GCM. Store only the ciphertext in MongoDB.
@Document(collection = "services")
public class ServiceConfig {
@Id
private String id;
private String name;
@Encrypted
private String apiKey;
// getters and setters
}
@Component
public class EncryptionConfig {
private final Cipher encryptCipher;
private final Cipher decryptCipher;
public EncryptionConfig(@Value("${enc.key:YOUR-32BYTE-BASE64-KEY-HERE}") String keyBase64) throws Exception {
byte[] key = Base64.getDecoder().decode(key);
SecretKeySpec spec = new SecretKeySpec(key, "AES");
this.encryptCipher = Cipher.getInstance("AES/GCM/NoPadding");
this.decryptCipher = Cipher.getInstance("AES/GCM/NoPadding");
}
@WritingConverter
public class EncryptedConverter implements Converter<String, Document> {
public Document convert(@NonNull String source) {
// encrypt and produce a Document with ciphertext + iv/tag
return new Document("v", 1).append("c", encrypt(source));
}
}
@ReadingConverter
public class DecryptedConverter implements Converter<Document, String> {
public String convert(@NonNull Document source) {
// decrypt using iv and ciphertext from Document
return decrypt(source.get("c", byte[].class), source.get("iv", byte[].class));
}
}
}
Register the converters in your MongoCustomConversions and ensure the encryption key is supplied via a secure vault or environment variable, not in source code.
2. Avoid embedding keys in connection strings
Do not place API keys directly in the MongoDB URI stored in application.properties. Instead, use separate credentials resolved at runtime. For example, set environment variables and reference them in your configuration:
# application.yml
spring:
data:
mongodb:
uri: mongodb://${MONGO_USER}:${MONGO_PASSWORD}@${MONGO_HOST}:${MONGO_PORT}/${MONGO_DB}
Then provide MONGO_USER and MONGO_PASSWORD securely via your deployment platform. Keep API keys separate from database credentials.
3. Use field-level access controls and auditing
Define MongoDB roles that grant only the necessary operations on specific collections. In your Spring Boot configuration, use a dedicated MongoDB user with minimal privileges. For auditing, enable logging on the MongoDB side to detect unauthorized read attempts on sensitive collections.
4. Sanitize outputs and avoid logging raw documents
When returning data from endpoints, exclude sensitive fields. With Spring MVC, use @JsonIgnore or DTO projections to prevent accidental serialization of keys.
@RestController
@RequestMapping("/api/services")
public class ServiceController {
private final ServiceRepository repository;
public ServiceController(ServiceRepository repository) {
this.repository = repository;
}
@GetMapping("/{id}")
public ResponseEntity<ServiceInfo> getService(@PathVariable String id) {
return repository.findById(id)
.map(doc -> ResponseEntity.ok(new ServiceInfo(doc.getName(), "**REDACTED**")))
.orElse(ResponseEntity.notFound().build());
}
}
record ServiceInfo(String name, String apiKeyMasked) { }
5. Validate and sanitize inputs
Use Spring Validator or annotations to ensure incoming filter objects do not allow path traversal or unintended queries that could return full documents with keys. Prefer explicit query construction over dynamic filters that directly map to MongoDB queries.
By encrypting keys before they reach MongoDB, avoiding plaintext connection strings, enforcing least-privilege access, and carefully controlling output, you significantly reduce the chances of API key exposure in a Spring Boot and MongoDB stack.