Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
There are many different kinds of mistakes that introduce information exposures. The severity of the error can range widely, depending on the context in which the product operates, the type of sensitive information that is revealed, and the benefits it may provide to an attacker.
この脆弱性の修正方法
14 件の Shoulder 検出ルールに基づく Information Exposure の予防策。
Use environment variables for configuration only; never log or return their values
package main import ( "log" "os" ) func main() { apiKey := os.Getenv("API_KEY") - log.Printf("API Key: %s", apiKey) + if apiKey == "" { + log.Fatal("API_KEY not configured") + } + log.Println("API key configured:", len(apiKey) > 0) + // Use apiKey internally, never log or return it }
Store API keys in environment variables, never log them, and protect model endpoints with authentication
- client := openai.NewClient("sk-proj-1234567890abcdefghijklmnop") - log.Printf("Using key: %s", apiKey) - http.Handle("/models/", http.FileServer(http.Dir("./models"))) + client := openai.NewClient(os.Getenv("OPENAI_API_KEY")) + log.Printf("Request completed: model=%s tokens=%d", model, usage.TotalTokens) + + modelsHandler := http.FileServer(http.Dir("./models")) + http.Handle("/models/", authMiddleware(rateLimiter(modelsHandler)))
Mask PII and redact credentials before sending data to LLM APIs, and use structured logging
- resp, _ := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ - Messages: []openai.ChatCompletionMessage{{ - Content: fmt.Sprintf("User SSN: %s, Password: %s", user.SSN, password), - }}, - }) - log.Printf("Request: %v", messages) + safeMessage := maskPII(userInput) + safeMessage = redactCredentials(safeMessage) + + resp, _ := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ + Messages: []openai.ChatCompletionMessage{{Content: safeMessage}}, + }) + log.Printf("Completed: model=%s tokens=%d", model, resp.Usage.TotalTokens)
Use secrets internally without exposing them in logs, responses, or client-side code
- app.get('/config', (req, res) => { - res.json({ apiKey: process.env.API_KEY }); - }); + const apiKey = process.env.API_KEY; + // Use the key server-side only + const result = await externalApi.call({ key: apiKey }); + res.json({ data: result });
Load API keys from environment variables and proxy LLM calls through your server
const openai = new OpenAI({ - apiKey: 'sk-proj-1234567890abcdefghijklmnop' + apiKey: process.env.OPENAI_API_KEY });
Mask or redact PII and credentials before sending data to LLM APIs
- const response = await openai.chat.completions.create({ - messages: [{ role: 'user', content: `Process: ${userRecord}` }] + const masked = maskPII(userRecord); + const response = await openai.chat.completions.create({ + messages: [{ role: 'user', content: `Process: ${masked}` }] });
Return generic error messages to users; log detailed errors server-side only
- from flask import jsonify - - @app.route('/api/data') - def handler(): - try: - return jsonify(process()) - except Exception as e: - return jsonify({'error': str(e), 'trace': traceback.format_exc()}), 500 + import logging + from flask import jsonify + + logger = logging.getLogger(__name__) + + @app.route('/api/data') + def handler(): + try: + return jsonify(process()) + except Exception as e: + logger.error(f"Error: {e}", exc_info=True) + return jsonify({'error': 'Internal server error'}), 500
Use Presidio or similar libraries to anonymize PII before sending data to LLM APIs
- messages = [{ - 'role': 'user', - 'content': f"User SSN: {user.ssn}, email: {user.email}. Summarize profile." - }] - logging.info(f"Request: {messages}") - response = openai.chat.completions.create(model='gpt-4', messages=messages) + from presidio_analyzer import AnalyzerEngine + from presidio_anonymizer import AnonymizerEngine + + analyzer = AnalyzerEngine() + anonymizer = AnonymizerEngine() + + def anonymize_text(text: str) -> str: + results = analyzer.analyze(text=text, language='en') + return anonymizer.anonymize(text=text, analyzer_results=results).text + + safe_message = anonymize_text(user_message) + messages = [{'role': 'user', 'content': safe_message}] + response = openai.chat.completions.create(model='gpt-4', messages=messages) + logger.info('Completed', extra={'model': 'gpt-4', 'tokens': response.usage.total_tokens})
Use explicit field selection or serializer schemas to exclude sensitive fields from responses
from flask import jsonify from models import User @app.route('/api/users') def get_users(): users = User.query.all() - return jsonify([u.__dict__ for u in users]) + return jsonify([{ + 'id': u.id, + 'email': u.email, + 'name': u.name + } for u in users])
コードの脆弱性を見つける
Shoulderを使用してコードのExposure of Sensitive Information to an Unauthorized Actorパターンをスキャンしましょう。 14 ルール.
# Scan with Shoulder CLI npx @shoulderdev/cli trust --cwe=200 # Or scan entire project npx @shoulderdev/cli trust .
検出ルール (14)
コードレビューで注目すべき点
これらのパターンはExposure of Sensitive Information to an Unauthorized Actorの潜在的な脆弱性を示しています。コードレビューとセキュリティ監査中に探してください。
コードベースをスキャン: Exposure of Sensitive Information to an Unauthorized Actor
Shoulder CLI はコードベース全体から脆弱なパターンを見つけます。