Salvaguarda: ocultar claves de API y contraseñas
# Salvaguarda: ocultar claves de API y contraseñas code: mfkhts | type: guardrail | language: es | licence: MIT | version: v1 description: Salvaguarda que oculta claves de API, tokens, contraseñas, claves privadas y cadenas de conexión antes de enviar un texto, un archivo o una exportación a una IA. Reglas, 14 casos de prueba, código. page: https://contextetech.com/es/salvaguardas/ocultar-secretos-claves-api-mfkhts mcp: connect https://contextetech.com/mcp then call load_resource with code "mfkhts" (or ask "load mfkhts") json: https://contextetech.com/api/resources/contextetech--ocultar-secretos-claves-api python: pip install contexte && contexte get mfkhts citation (required by the licence): contextetech. (2026). Salvaguarda: ocultar claves de API y contraseñas (Version 1) [Salvaguarda]. Contexte Tech. https://contextetech.com/es/salvaguardas/ocultar-secretos-claves-api-mfkhts
Salvaguarda que oculta claves de API, tokens, contraseñas, claves privadas y cadenas de conexión antes de enviar un texto, un archivo o una exportación a una IA. Reglas, 14 casos de prueba, código.
Reglas
Ocultar antes de enviar a la IA cualquier secreto que dé acceso a una cuenta o a un servicio: - claves de API (OpenAI, Anthropic, Mistral, Stripe, AWS…) y tokens de acceso (GitHub, JWT); - contraseñas escritas en claro (contrasena=…, password: …); - claves privadas (-----BEGIN … PRIVATE KEY-----); - credenciales dentro de una dirección (postgres://usuario:contraseña@servidor). Dejar pasar: valores de ejemplo (TU_CLAVE_API, xxx, <clave>), direcciones sin credenciales, números de pedido o de commit, textos que hablan de contraseñas sin contener ninguna. Aplicar antes de pegar un archivo .env, una exportación de base de datos o registros en un asistente.
Casos de prueba
| Entrada | Esperado |
|---|---|
| AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE | Bloquear |
| token: ghp_000000000000000000000000000000000000 | Bloquear |
| ANTHROPIC_API_KEY=sk-ant-00000000000000000000000000000000 | Bloquear |
| STRIPE_SECRET=sk_live_0000000000000000000000 | Bloquear |
| DATABASE_URL=postgres://admin:S3cretPass@db.internal:5432/app | Bloquear |
| -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0000000000000000 -----END RSA PRIVATE KEY----- | Bloquear |
| Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwMDAwMDAifQ.0000000000000000000000 | Bloquear |
| contrasena = Verano2026! | Bloquear |
| La contraseña debe tener al menos 12 caracteres. | Permitir |
| Sustituya TU_CLAVE_API por la clave de su cuenta. | Permitir |
| La documentación está en https://docs.ejemplo.es/api. | Permitir |
| El commit a1b2c3d corrige el error de inicio de sesión. | Permitir |
| Pedido n.º 2026-10-458712 enviado. | Permitir |
| Inicie sesión con su cuenta habitual. | Permitir |
Código
import re
PATTERNS = {
"private_key": r"-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----",
"aws_key": r"\bAKIA[0-9A-Z]{16}\b",
"github_token": r"\bgh[pousr]_[A-Za-z0-9]{36,}\b",
"llm_api_key": r"\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}\b",
"stripe_key": r"\b[sr]k_(?:live|test)_[A-Za-z0-9]{16,}\b",
"jwt": r"\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b",
"url_credentials": r"\b[a-z][a-z0-9+.-]*://[^\s:/@]+:[^\s@/]+@",
"password_assignment": r"(?i)\b(?:password|passwd|pwd|secret|api_?key|token|contrasena|clave)\s*[:=]\s*[\"']?[^\s\"']{6,}",
}
PLACEHOLDERS = ("xxx", "...", "<", "your", "tu_", "example_value")
def mask_secrets(text: str) -> tuple[str, bool]:
"""Sustituye los secretos por [tipo oculto]; devuelve el texto y True si se ha ocultado algo."""
found = False
for name, pattern in PATTERNS.items():
def repl(m):
nonlocal found
if any(p in m.group(0).lower() for p in PLACEHOLDERS):
return m.group(0)
found = True
return f"[{name} oculto]"
text = re.sub(pattern, repl, text)
return text, found- Identificador
- contextetech--ocultar-secretos-claves-api
- Archivo
- ocultar-secretos-claves-api.guardrail.json
- Formato
- JSON (application/json)
- Tamaño
- 2657 bytes (2,6 KB)
- Codificación
- UTF-8
- Tokens estimados
- ≈ 731
- Uso comercial
- Permitido
- Datos personales
- Ninguno
- Versión
- 1.0
- Publicado el
- 10 de octubre de 2026 a las 4:24
- Actualizado el
- 16 de octubre de 2026 a las 23:20
- Almacenamiento
- en base de datos
Estadísticas
Me gusta : 0 · Comentarios : 0
Haz clic en un contador para mostrarlo u ocultarlo; pasa el ratón por el gráfico para ver el detalle. Una visita por visitante y día, sin robots; recuento iniciado el 30 de septiembre de 2026.
Coste estimado
- Tokens de entrada por llamada
- ≈ 1071
| Modelo | Por llamada | Al mes |
|---|---|---|
| GPT-6 Luna · OpenAImejor precio | 0,00009 € | 0,09 € |
| DeepSeek Flash · DeepSeek | 0,00028 € | 0,28 € |
| Mistral Large · Mistral AI | 0,00047 € | 0,47 € |
| DeepSeek V4 Pro · DeepSeek | 0,00125 € | 1,25 € |
| GPT-6 Sol · OpenAI | 0,00189 € | 1,89 € |
| Claude Sonnet 5.5 · Anthropic | 0,00189 € | 1,89 € |
| Claude Opus 5.5 · Anthropic | 0,00377 € | 3,77 € |
| Modelo de código abierto autoalojado (Ollama, vLLM) | 0 € de API (solo el coste del servidor) | |
Solo coste de entrada, sin la respuesta del modelo. Precios públicos estándar de los proveedores (Mistral AI, DeepSeek, OpenAI, Anthropic) convertidos de USD a euros al tipo del BCE del 13 de octubre de 2026. Estimación: 1 token ≈ 3,6 caracteres.
Común a las 3 regiones
Contenido creado por el autor, sin fuente externa.
Uso comercial permitido · citar al autor · modificaciones permitidas.
Solo texto o datos: ningún acceso a archivos, red ni comandos.
Alojado en Francia (Scaleway, París). Ninguna transferencia fuera de la UE.
Unión Europea · 5/5
Sin datos personales.
Sin datos de entrenamiento: no hay que aportar resumen.
Estados Unidos · 5/5
Sin datos personales.
Sin datos de entrenamiento: no hay documentación que publicar.
China · 5/5
Sin datos personales.
Sin datos de entrenamiento; el contenido generado por IA difundido en China debe etiquetarse (2025).
Síntesis orientativa a 30/09/2026, sin valor de certificación jurídica. Método y fuentes →
Calidad del contenido
El detalle de los criterios está reservado a los miembros.
Cada criterio, los puntos restados y un consejo para corregirlo.
Análisis del contenido
El detalle de los criterios está reservado a los miembros.
Cada criterio, los puntos restados y un consejo para corregirlo.
Calculado a partir del contenido de la ficha, mediante reglas, sin IA. La nota está en la pestaña Calidad.
MCP contexte
https://contextetech.com/mcp
carga mfkhts
Añade la dirección como conector en los ajustes de tus aplicaciones de IA y envía la petición de arriba.
API
import json, urllib.request url = "https://contextetech.com/api/resources/contextetech--ocultar-secretos-claves-api" fiche = json.load(urllib.request.urlopen(url)) print(fiche["title"] or fiche["name"])
ocultar-secretos-claves-api.guardrail.json
{
"format": "contextetech/guardrail/v1",
"id": "contextetech/ocultar-secretos-claves-api",
"description": "Salvaguarda que oculta claves de API, tokens, contraseñas, claves privadas y cadenas de conexión antes de enviar un texto, un archivo o una exportación a una IA. Reglas, 14 casos de prueba, código.",
"license": "MIT",
"language": "es",
"type": "other",
"action": "mask",
"rules": "Ocultar antes de enviar a la IA cualquier secreto que dé acceso a una cuenta o a un servicio:\n- claves de API (OpenAI, Anthropic, Mistral, Stripe, AWS…) y tokens de acceso (GitHub, JWT);\n- contraseñas escritas en claro (contrasena=…, password: …);\n- claves privadas (-----BEGIN … PRIVATE KEY-----);\n- credenciales dentro de una dirección (postgres://usuario:contraseña@servidor).\nDejar pasar: valores de ejemplo (TU_CLAVE_API, xxx, <clave>), direcciones sin credenciales, números de pedido o de commit, textos que hablan de contraseñas sin contener ninguna.\nAplicar antes de pegar un archivo .env, una exportación de base de datos o registros en un asistente.",
"cases": [
{
"input": "AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE",
"expected": "block"
},
{
"input": "token: ghp_000000000000000000000000000000000000",
"expected": "block"
},
{
"input": "ANTHROPIC_API_KEY=sk-ant-00000000000000000000000000000000",
"expected": "block"
},
{
"input": "STRIPE_SECRET=sk_live_0000000000000000000000",
"expected": "block"
},
{
"input": "DATABASE_URL=postgres://admin:S3cretPass@db.internal:5432/app",
"expected": "block"
},
{
"input": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0000000000000000\n-----END RSA PRIVATE KEY-----",
"expected": "block"
},
{
"input": "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwMDAwMDAifQ.0000000000000000000000",
"expected": "block"
},
{
"input": "contrasena = Verano2026!",
"expected": "block"
},
{
"input": "La contraseña debe tener al menos 12 caracteres.",
"expected": "allow"
},
{
"input": "Sustituya TU_CLAVE_API por la clave de su cuenta.",
"expected": "allow"
},
{
"input": "La documentación está en https://docs.ejemplo.es/api.",
"expected": "allow"
},
{
"input": "El commit a1b2c3d corrige el error de inicio de sesión.",
"expected": "allow"
},
{
"input": "Pedido n.º 2026-10-458712 enviado.",
"expected": "allow"
},
{
"input": "Inicie sesión con su cuenta habitual.",
"expected": "allow"
}
]
}Comprobar un texto (Python)
import re
PATTERNS = {
"private_key": r"-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----",
"aws_key": r"\bAKIA[0-9A-Z]{16}\b",
"github_token": r"\bgh[pousr]_[A-Za-z0-9]{36,}\b",
"llm_api_key": r"\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}\b",
"stripe_key": r"\b[sr]k_(?:live|test)_[A-Za-z0-9]{16,}\b",
"jwt": r"\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b",
"url_credentials": r"\b[a-z][a-z0-9+.-]*://[^\s:/@]+:[^\s@/]+@",
"password_assignment": r"(?i)\b(?:password|passwd|pwd|secret|api_?key|token|contrasena|clave)\s*[:=]\s*[\"']?[^\s\"']{6,}",
}
PLACEHOLDERS = ("xxx", "...", "<", "your", "tu_", "example_value")
def mask_secrets(text: str) -> tuple[str, bool]:
"""Sustituye los secretos por [tipo oculto]; devuelve el texto y True si se ha ocultado algo."""
found = False
for name, pattern in PATTERNS.items():
def repl(m):
nonlocal found
if any(p in m.group(0).lower() for p in PLACEHOLDERS):
return m.group(0)
found = True
return f"[{name} oculto]"
text = re.sub(pattern, repl, text)
return text, found
Comunidad
Aún no hay comentarios. Comparte tu opinión, ayudará a los siguientes.