로그 파싱·군집·이상탐지·추출·위생검사 — 외부 의존성 0, 한국 PII 우선, 에이전트 네이티브 JSON. Parse, cluster, anomaly-detect, extract, and audit log lines with zero external dependencies and Korean-first PII detection.
Compatible Platforms any
✅ No security risks found.
AI Review Stage
스킬 메타데이터와 코드 파일을 종합적으로 검토한 결과, 다음과 같은 판단 근거로 안전하다고 판단합니다. 1. **권한 일치**: 메타데이터에 `network: false`, `filesystem: false`, `subprocess: false`로 명확히 선언되어 있으며, 제공된 코드 파일(`main.py`, `lib/*.py`) 어디에서도 외부 네트워크 통신, 파일 시스템 접근, 외부 프로세스 실행을 시도하는 코드가 발견되지 않았습니다. 이는 선언된 권한과 실제 코드가 완벽하게 일치함을 의미합니다. 2. **악의적 코드 없음**: 코드 구조는 명확하고 모듈화되어 있으며, 난독화된 부분이 없습니다. 정적 분석 결과에서도 `red_flags_found`, `obfuscation_warnings`, `forbidden_exec_files_found`가 모두 비어 있어 악의적인 목적의 코드가 없음을 뒷받침합니다. 데이터 탈취나 시스템 파괴와 같은 행위를 할 수 있는 기능이 없습니다. 3. **외부 통신 없음**: `network: false` 선언과 코드 검토를 통해 외부 통신이 전혀 없음을 확인했습니다. 4. **데이터 무단 수집/전송 없음**: 스킬은 표준 입력을 통해 로그 데이터를 받아 처리하고, 결과를 표준 출력으로 반환하는 `stdin_stdout` 패턴을 따릅니다. 외부 통신이 없으므로 사용자 데이터를 무단으로 수집하거나 전송할 수 없습니다. 5. **코드 품질 및 목적 일치**: 스킬은 '외부 의존성 0'을 명시하고 있으며, `requirements.python_packages`가 비어 있어 이를 준수합니다. 모든 기능은 Python 표준 라이브러리 내에서 구현되었습니다. 로그 파싱, 군집화, 이상 탐지, 필드 추출, 한국 PII(주민등록번호, 사업자등록번호 등)를 포함한 위생 검사 등 스킬의 목적에 부합하는 기능들이 체계적으로 구현되어 있습니다. `MAX_LINES_DEFAULT` 및 `MAX_BYTES` 제한을 통해 잠재적인 리소스 고갈 공격에 대한 방어 메커니즘도 갖추고 있습니다. 결론적으로, 이 스킬은 선언된 보안 정책을 철저히 준수하며, 악의적인 행위를 할 가능성이 없어 안전하게 스토어에 공개될 수 있습니다.
Representative input/output examples for this skill. Agents can use these to understand how to invoke the skill and what output to expect.
nginx access log 라인을 구조화된 JSON 레코드로 변환합니다. 포맷 자동 감지.
{
"action": "parse",
"language": "ko",
"lines": [
"192.168.1.1 - alice [10/Apr/2025:13:55:36 +0900] \"GET /api/users HTTP/1.1\" 200 1234 \"-\" \"Mozilla/5.0\"",
"10.0.0.5 - - [10/Apr/2025:13:55:37 +0900] \"POST /api/login HTTP/1.1\" 401 89 \"-\" \"curl/7.64.1\""
]
}
{
"action": "parse",
"parsed": [
{
"fields": {
"body_bytes": 1234,
"method": "GET",
"path": "/api/users",
"protocol": "HTTP/1.1",
"referer": "-",
"remote_addr": "192.168.1.1",
"remote_user": "alice",
"status": 200,
"user_agent": "Mozilla/5.0"
},
"format_detected": "nginx",
"level": "INFO",
"line_no": 1,
"message": "GET /api/users HTTP/1.1",
"raw": "192.168.1.1 - alice [10/Apr/2025:13:55:36 +0900] \"GET /api/users HTTP/1.1\" 200 1234 \"-\" \"Mozilla/5.0\"",
"source": "192.168.1.1",
"timestamp": "2025-04-10T13:55:36+09:00"
},
{
"fields": {
"body_bytes": 89,
"method": "POST",
"path": "/api/login",
"protocol": "HTTP/1.1",
"referer": "-",
"remote_addr": "10.0.0.5",
"remote_user": null,
"status": 401,
"user_agent": "curl/7.64.1"
},
"format_detected": "nginx",
"level": "WARN",
"line_no": 2,
"message": "POST /api/login HTTP/1.1",
"raw": "10.0.0.5 - - [10/Apr/2025:13:55:37 +0900] \"POST /api/login HTTP/1.1\" 401 89 \"-\" \"curl/7.64.1\"",
"source": "10.0.0.5",
"timestamp": "2025-04-10T13:55:37+09:00"
}
],
"total_lines": 2
}
비슷한 로그 메시지를 군집화하고 템플릿을 추출합니다.
{
"action": "cluster",
"language": "ko",
"lines": [
"2025-04-10 13:00:01 INFO [app] User 1001 logged in from 192.168.1.1",
"2025-04-10 13:00:05 INFO [app] User 1002 logged in from 10.0.0.1",
"2025-04-10 13:00:10 INFO [app] User 9999 logged in from 172.16.0.1",
"2025-04-10 13:01:00 ERROR [db] Connection timeout after 30s retries=3",
"2025-04-10 13:01:05 ERROR [db] Connection timeout after 60s retries=5"
],
"min_cluster_size": 2
}
{
"action": "cluster",
"clusters": [
{
"cluster_id": 1,
"count": 3,
"examples": [
"User 1001 logged in from 192.168.1.1",
"User 1002 logged in from 10.0.0.1"
],
"first_seen": "2025-04-10T13:00:01",
"last_seen": "2025-04-10T13:00:10",
"template": "User \u003c*\u003e logged in from \u003c*\u003e",
"variability_score": 0.67
},
{
"cluster_id": 2,
"count": 2,
"examples": [
"Connection timeout after 30s retries=3"
],
"first_seen": "2025-04-10T13:01:00",
"last_seen": "2025-04-10T13:01:05",
"template": "Connection timeout after \u003c*\u003e retries=\u003c*\u003e",
"variability_score": 0.5
}
],
"total_lines": 5
}
시간대별 로그 빈도 분석으로 ERROR 급증과 신규 패턴을 탐지합니다.
{
"action": "anomaly",
"error_ratio_threshold": 0.5,
"language": "ko",
"lines": [
"2025-04-10 13:00:01 INFO [app] request processed",
"2025-04-10 13:00:02 INFO [app] request processed",
"2025-04-10 13:05:01 ERROR [db] disk full",
"2025-04-10 13:05:02 ERROR [db] disk full",
"2025-04-10 13:05:03 ERROR [db] disk full",
"2025-04-10 13:05:04 ERROR [db] disk full",
"2025-04-10 13:05:05 FATAL [sys] OOM killer activated pid=1234"
],
"window_minutes": 5,
"zscore_threshold": 2.0
}
{
"action": "anomaly",
"anomalies": [
{
"affected_lines": [
3,
4,
5,
6,
7
],
"description_en": "ERROR/FATAL ratio exceeds threshold (71.4% \u003e 50.0%)",
"description_ko": "ERROR/FATAL \ube44\uc728\uc774 \uc784\uacc4\uac12\uc744 \ucd08\uacfc\ud588\uc2b5\ub2c8\ub2e4 (71.4% \u003e 50.0%)",
"severity": "critical",
"threshold": 0.5,
"type": "high_error_ratio",
"value": 0.714,
"window_end": "2025-04-10T13:05:05",
"window_start": "2025-04-10T13:05:01"
},
{
"affected_lines": [
7
],
"description_en": "New log template appeared: \u0027OOM killer activated pid=\u003c*\u003e\u0027",
"description_ko": "\uc2e0\uaddc \ub85c\uadf8 \ud15c\ud50c\ub9bf \ucd9c\ud604: \u0027OOM killer activated pid=\u003c*\u003e\u0027",
"severity": "high",
"threshold": 0.0,
"type": "new_template",
"value": 1.0,
"window_end": "2025-04-10T13:05:05",
"window_start": "2025-04-10T13:05:05"
}
],
"total_lines": 7
}
로그에서 IP 주소, URL, 레이턴시(ms) 값을 추출합니다.
{
"action": "extract",
"extract_fields": [
"ip_addresses",
"urls",
"latency_ms"
],
"language": "ko",
"lines": [
"2025-04-10 13:00:01 INFO request from 192.168.1.1 to https://api.example.com/v1/users took 152ms",
"2025-04-10 13:00:02 WARN slow query from 10.0.0.5, latency=3200ms, url=http://db.internal/query"
]
}
{
"action": "extract",
"extracted": {
"ip_addresses": [
{
"line_no": 1,
"value": "192.168.1.1"
},
{
"line_no": 2,
"value": "10.0.0.5"
}
],
"latency_ms": [
{
"line_no": 1,
"raw": "152ms",
"value": 152
},
{
"line_no": 2,
"raw": "3200ms",
"value": 3200
}
],
"urls": [
{
"line_no": 1,
"value": "https://api.example.com/v1/users"
},
{
"line_no": 2,
"value": "http://db.internal/query"
}
]
},
"total_lines": 2
}
로그에서 한국 주민번호 패턴을 탐지하고 수정 힌트를 제공합니다.
{
"action": "audit",
"language": "ko",
"lines": [
"2025-04-10 INFO user registered: name=\ud64d\uae38\ub3d9 ssn=900101-1234567 email=hong@example.com",
"2025-04-10 INFO payment: card=4111-1111-1111-1111 amount=50000"
]
}
{
"action": "audit",
"audit_findings": [
{
"affected_lines": [
1
],
"category": "SEC",
"fix_hint": {
"action": "\ub9c8\uc2a4\ud0b9 \ucc98\ub9ac",
"location": "\ub77c\uc778 1, ssn \ud544\ub4dc",
"reference": "https://www.pipc.go.kr/np/default/page.do?mCode=C020010000",
"suggested_replacement": "900101-*******"
},
"message_en": "Korean national ID number detected in log. Immediate masking required.",
"message_ko": "\ub85c\uadf8\uc5d0 \uc8fc\ubbfc\ub4f1\ub85d\ubc88\ud638 \ud328\ud134\uc774 \uac10\uc9c0\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc989\uc2dc \ub9c8\uc2a4\ud0b9 \ud544\uc694.",
"rule_id": "SEC-KR-SSN",
"sample_value": "900101-1234567",
"severity": "critical",
"title_en": "Korean SSN (\uc8fc\ubbfc\ubc88\ud638) Exposure",
"title_ko": "\ud55c\uad6d \uc8fc\ubbfc\ub4f1\ub85d\ubc88\ud638 \ub178\ucd9c"
},
{
"affected_lines": [
2
],
"category": "SEC",
"fix_hint": {
"action": "\ub9c8\uc2a4\ud0b9 \ucc98\ub9ac",
"location": "\ub77c\uc778 2, card \ud544\ub4dc",
"reference": "https://www.pci-sss.org/en/documents/pci-dss",
"suggested_replacement": "4111-****-****-1111"
},
"message_en": "Card number pattern passing Luhn check detected in log.",
"message_ko": "Luhn \uac80\uc99d\uc744 \ud1b5\uacfc\ud558\ub294 \uce74\ub4dc\ubc88\ud638 \ud328\ud134\uc774 \uac10\uc9c0\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"rule_id": "SEC-CARD-NUMBER",
"sample_value": "4111-1111-1111-1111",
"severity": "critical",
"title_en": "Credit/Debit Card Number Exposure",
"title_ko": "\uce74\ub4dc\ubc88\ud638 \ub178\ucd9c"
}
],
"audit_summary": {
"critical_count": 2,
"high_count": 0,
"low_count": 0,
"medium_count": 0,
"passed": false,
"risk_level": "critical",
"total_findings": 2
},
"total_lines": 2
}
로그에서 API 키, 패스워드, JWT 토큰 노출을 탐지합니다.
{
"action": "audit",
"language": "ko",
"lines": [
"2025-04-10 DEBUG config loaded: OPENAI_API_KEY=sk-proj-AbCdEfGhIjKlMnOpQrStUvWx",
"2025-04-10 INFO login attempt: user=admin password=P@ssw0rd123!",
"2025-04-10 DEBUG auth header: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0In0.abc"
]
}
{
"action": "audit",
"audit_findings": [
{
"affected_lines": [
1
],
"category": "SEC",
"fix_hint": {
"action": "\ud658\uacbd\ubcc0\uc218 \ub610\ub294 \uc2dc\ud06c\ub9bf \ub9e4\ub2c8\uc800\ub85c \uc774\ub3d9",
"location": "\ub77c\uc778 1, OPENAI_API_KEY",
"reference": "https://owasp.org/www-community/vulnerabilities/Exposed_Sensitive_Information",
"suggested_replacement": "OPENAI_API_KEY=sk-proj-***"
},
"message_en": "Known API key pattern (sk-proj-...) exposed in log.",
"message_ko": "\uc54c\ub824\uc9c4 API \ud0a4 \ud328\ud134(sk-proj-...)\uc774 \ub85c\uadf8\uc5d0 \ub178\ucd9c\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"rule_id": "SEC-API-KEY",
"sample_value": "sk-proj-AbCdEfGhI...",
"severity": "critical",
"title_en": "API Key Exposure",
"title_ko": "API \ud0a4 \ub178\ucd9c"
},
{
"affected_lines": [
2
],
"category": "SEC",
"fix_hint": {
"action": "\ub85c\uae45 \uc804 \ub9c8\uc2a4\ud0b9",
"location": "\ub77c\uc778 2",
"reference": "https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html",
"suggested_replacement": "password=***"
},
"message_en": "Plaintext value after password= field found in log.",
"message_ko": "password= \ud328\ud134 \ub4a4\uc5d0 \ud3c9\ubb38 \uac12\uc774 \ub85c\uadf8\uc5d0 \ucd9c\ub825\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"rule_id": "SEC-PASSWORD-FIELD",
"sample_value": "password=P@ssw0rd123!",
"severity": "high",
"title_en": "Password Field Exposure",
"title_ko": "\ud328\uc2a4\uc6cc\ub4dc \ud544\ub4dc \ub178\ucd9c"
},
{
"affected_lines": [
3
],
"category": "SEC",
"fix_hint": {
"action": "\ud1a0\ud070 \ub9c8\uc2a4\ud0b9 \ub610\ub294 \ub85c\uae45 \uc81c\uac70",
"location": "\ub77c\uc778 3, auth header",
"reference": "https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html",
"suggested_replacement": "Bearer eyJhbGci...***"
},
"message_en": "JWT token found in Bearer header or Authorization field.",
"message_ko": "Bearer \ud5e4\ub354 \ub610\ub294 Authorization \ud544\ub4dc\uc5d0 JWT \ud1a0\ud070\uc774 \ud3ec\ud568\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.",
"rule_id": "SEC-JWT",
"sample_value": "eyJhbGci...",
"severity": "high",
"title_en": "JWT Token Exposure",
"title_ko": "JWT \ud1a0\ud070 \ub178\ucd9c"
}
],
"audit_summary": {
"critical_count": 1,
"high_count": 2,
"low_count": 0,
"medium_count": 0,
"passed": false,
"risk_level": "critical",
"total_findings": 3
},
"total_lines": 3
}
Java/Python 예외 스택 트레이스와 request ID를 추출합니다.
{
"action": "extract",
"extract_fields": [
"request_ids",
"stack_traces",
"latency_ms",
"status_codes"
],
"language": "ko",
"lines": [
"2025-04-10 13:00:01 ERROR [req-abc123] NullPointerException at com.example.UserService.getUser(UserService.java:42)",
"\tat com.example.UserService.getUser(UserService.java:42)",
"\tat com.example.ApiController.handle(ApiController.java:18)",
"2025-04-10 13:00:02 INFO [req-def456] request completed in 250ms status=200"
]
}
{
"action": "extract",
"extracted": {
"latency_ms": [
{
"line_no": 4,
"raw": "250ms",
"value": 250
}
],
"request_ids": [
{
"line_no": 1,
"value": "req-abc123"
},
{
"line_no": 4,
"value": "req-def456"
}
],
"stack_traces": [
{
"exception_type": "NullPointerException",
"frame_count": 2,
"line_nos": [
1,
2,
3
],
"value": "NullPointerException at com.example.UserService.getUser(UserService.java:42)"
}
],
"status_codes": [
{
"line_no": 4,
"value": 200
}
]
},
"total_lines": 4
}
QUAL 규칙으로 타임스탬프 누락, 줄 길이 초과, 레벨 표기 불일치를 감지합니다.
{
"action": "audit",
"audit_rules": [
"QUAL-NO-TIMESTAMP",
"QUAL-LEVEL-INCONSISTENT"
],
"language": "ko",
"lines": [
"INFO [app] server started",
"2025-04-10 13:00:01 info [app] request received",
"2025-04-10 13:00:02 WARNING [app] slow query detected"
]
}
{
"action": "audit",
"audit_findings": [
{
"affected_lines": [
1
],
"category": "QUAL",
"fix_hint": {
"action": "\ud0c0\uc784\uc2a4\ud0ec\ud504 \ucd94\uac00",
"location": "\ub77c\uc778 1",
"reference": "https://www.rfc-editor.org/rfc/rfc3339",
"suggested_replacement": "2025-04-10T13:00:00Z INFO [app] server started"
},
"message_en": "Log line has no recognizable timestamp.",
"message_ko": "\ub85c\uadf8 \ub77c\uc778\uc5d0 \uc778\uc2dd \uac00\ub2a5\ud55c \ud0c0\uc784\uc2a4\ud0ec\ud504\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.",
"rule_id": "QUAL-NO-TIMESTAMP",
"sample_value": "INFO [app] server started",
"severity": "medium",
"title_en": "Missing Timestamp",
"title_ko": "\ud0c0\uc784\uc2a4\ud0ec\ud504 \ub204\ub77d"
},
{
"affected_lines": [
2,
3
],
"category": "QUAL",
"fix_hint": {
"action": "\ub808\ubca8 \ud45c\uae30 \ud1b5\uc77c",
"location": "\ub77c\uc778 2, 3",
"reference": "https://www.rfc-editor.org/rfc/rfc5424#section-6.2.1",
"suggested_replacement": "INFO, WARN"
},
"message_en": "Log level casing is inconsistent across lines (INFO, info, WARNING, etc.).",
"message_ko": "\ub85c\uadf8 \ub808\ubca8 \ud45c\uae30\uac00 \ub300\uc18c\ubb38\uc790 \ud63c\uc6a9\ub418\uc5c8\uc2b5\ub2c8\ub2e4 (INFO, info, WARNING \ub4f1).",
"rule_id": "QUAL-LEVEL-INCONSISTENT",
"sample_value": "info, WARNING",
"severity": "low",
"title_en": "Inconsistent Log Level Casing",
"title_ko": "\ub808\ubca8 \ud45c\uae30 \ubd88\uc77c\uce58"
}
],
"audit_summary": {
"critical_count": 0,
"high_count": 0,
"low_count": 1,
"medium_count": 1,
"passed": true,
"risk_level": "low",
"total_findings": 2
},
"total_lines": 3
}
All examples are also available via the agent API:
/v1/agent/skills/690f5ed4-c931-4fa7-98e9-0d1143cd8b37/schema
No reviews yet. Be the first to leave one!