skills/openharmony-security-review/SKILL.md
Use when reviewing OpenHarmony C++ system service code for security vulnerabilities, particularly IPC handlers, multithreaded components, or code handling sensitive user data
npx skillsauth add openharmonyinsight/openharmony-skills openharmony-security-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
OpenHarmony system services run with high privileges and handle untrusted inputs via IPC and network interfaces. This skill provides a structured approach to identifying critical security vulnerabilities in four key areas: external input handling, multithreading race conditions, sensitive information leakage, and permission validation.
digraph when_to_use {
"Reviewing OpenHarmony code?" [shape=diamond];
"Is it C++ system service?" [shape=diamond];
"Handles IPC/network data?" [shape=diamond];
"Has shared state?" [shape=diamond];
"Logs data?" [shape=diamond];
"Use this skill" [shape=box];
"Different skill needed" [shape=box];
"Reviewing OpenHarmony code?" -> "Different skill needed" [label="no"];
"Reviewing OpenHarmony code?" -> "Is it C++ system service?" [label="yes"];
"Is it C++ system service?" -> "Different skill needed" [label="no"];
"Is it C++ system service?" -> "Handles IPC/network data?" [label="yes"];
"Handles IPC/network data?" -> "Use this skill" [label="yes"];
"Handles IPC/network data?" -> "Has shared state?" [label="no"];
"Has shared state?" -> "Use this skill" [label="yes"];
"Has shared state?" -> "Logs data?" [label="no"];
"Logs data?" -> "Use this skill" [label="yes"];
"Logs data?" -> "Different skill needed" [label="no"];
}
Use this skill when:
Do NOT use for:
Header file input (.h/.hpp): Analyze corresponding xxxService.cpp and xxxStub.cpp Stub file input (xxxStub.cpp): Extend analysis to xxxService.cpp (core logic + shared state) External calls: Flag cross-component concurrency risks for separate review
| Category | Critical Checks | Severity |
|----------|----------------|----------|
| IPC Deserialization | All MessageParcel reads checked for success | HIGH |
| Logical Validation | Array lengths/indices validated AFTER deserialization | HIGH |
| Integer Bounds | Size variables: 0 <= size <= MAX_ALLOWED_BUFFER | HIGH |
| Object Lifecycle | RemoteObjects/fd validated before use (nullptr check) | HIGH |
| Parser Security | Network parsers reject malformed input, prevent recursion attacks | HIGH |
| Container Thread Safety | All container operations protected (read/write, write/write) | HIGH |
| Iterator Invalidation** | No modification while iterating | HIGH |
| Lock Consistency | All shared state access protected by mutex | HIGH |
| Deadlock Risk | Nested locks acquired in consistent order | HIGH |
| TOCTOU | State checks immediately followed by dependent action | HIGH |
| PII in Logs | No phone numbers, contacts, SMS, biometrics in logs | HIGH |
| Input Events in Logs** | No raw KeyEvents, touch coordinates, screen bounds | HIGH |
| Pointer Addresses | No %p or &variable in logs (ASLR bypass) | HIGH |
| Permission Check | All privileged operations validate caller permissions | HIGH |
Rule: Every MessageParcel read operation must check return value.
Anti-pattern:
// ❌ VULNERABLE: No validation
parcel.ReadInt32(val);
int32_t size = parcel.ReadInt32();
Required pattern:
// ✅ SECURE: Always check return value
if (!parcel.ReadInt32(val)) {
HILOG_ERROR("Failed to read value");
return ERR_INVALID_DATA;
}
if (!parcel.ReadInt32(size)) {
HILOG_ERROR("Failed to read size");
return ERR_INVALID_DATA;
}
Verification: Confirm read data size matches expected type size. Stop processing immediately on read failure.
Rule: After deserializing, validate values are within logical bounds BEFORE use.
Attack vector: Attacker sends size = 0xFFFFFFFF to cause memory exhaustion or integer overflow in new char[size].
Anti-pattern:
// ❌ VULNERABLE: No bounds validation
int32_t size = parcel.ReadInt32();
std::vector<char> buffer(size); // May allocate gigabytes or overflow
Required pattern:
// ✅ SECURE: Validate bounds immediately
int32_t size = 0;
if (!parcel.ReadInt32(size)) {
return ERR_INVALID_DATA;
}
constexpr int32_t MAX_ALLOWED_BUFFER = 1024 * 1024; // 1MB
if (size < 0 || size > MAX_ALLOWED_BUFFER) {
HILOG_ERROR("Invalid size: %{public}d", size);
return ERR_INVALID_DATA;
}
std::vector<char> buffer(size);
Validation targets: Array lengths, indices, loop counters, buffer sizes
Rule: Validate RemoteObjects and file descriptors before use.
Required pattern:
// ✅ SECURE: Validate before use
if (remoteObject == nullptr) {
HILOG_ERROR("Received null RemoteObject");
return ERR_NULL_OBJECT;
}
if (fd < 0) {
HILOG_ERROR("Invalid file descriptor");
return ERR_INVALID_FD;
}
Rule: Network parsers must reject malformed input and prevent recursion attacks.
Checks:
Rule: All concurrent container operations must be protected by locks.
Critical risks:
Anti-pattern:
// ❌ VULNERABLE: Unprotected concurrent access
std::vector<int> items_;
void AddItem(int item) {
items_.push_back(item); // Unsafe if called concurrently
}
void ProcessItems() {
for (auto& item : items_) { // Iteration
// If AddItem called here, iterator invalidates → CRASH
}
}
Required pattern:
// ✅ SECURE: All access protected
std::vector<int> items_;
std::mutex itemsMutex_;
void AddItem(int item) {
std::lock_guard<std::mutex> lock(itemsMutex_);
items_.push_back(item);
}
void ProcessItems() {
std::lock_guard<std::mutex> lock(itemsMutex_);
for (auto& item : items_) {
// Safe - lock held during iteration
}
}
Container types to scrutinize: std::vector, std::map, std::list, std::unordered_map, std::string
Scrutinize operations: push_back, insert, erase, operator[], at, iteration
Rule: All shared resources must be consistently protected.
Shared resources requiring protection:
Lock types: std::mutex, std::shared_mutex, SpinLock
Anti-pattern:
// ❌ VULNERABLE: Inconsistent protection
class Service {
std::map<int, Data> dataMap_;
std::mutex mutex_;
void Update(int key, const Data& data) {
std::lock_guard<std::mutex> lock(mutex_);
dataMap_[key] = data;
}
Data Lookup(int key) {
// ❌ NO LOCK - race condition with Update
return dataMap_[key];
}
};
Required pattern:
// ✅ SECURE: Consistent protection
class Service {
std::map<int, Data> dataMap_;
std::mutex mutex_;
void Update(int key, const Data& data) {
std::lock_guard<std::mutex> lock(mutex_);
dataMap_[key] = data;
}
Data Lookup(int key) {
std::lock_guard<std::mutex> lock(mutex_);
return dataMap_[key];
}
};
Rule: Assess deadlock risk in nested lock scenarios.
Deadlock conditions:
Anti-pattern:
// ❌ VULNERABLE: Deadlock risk
void Path1() {
std::lock_guard<std::mutex> lock1(mutex1_);
std::lock_guard<std::mutex> lock2(mutex2_); // Order: 1 then 2
}
void Path2() {
std::lock_guard<std::mutex> lock2(mutex2_);
std::lock_guard<std::mutex> lock1(mutex1_); // Order: 2 then 1 → DEADLOCK
}
Required pattern:
// ✅ SECURE: Consistent lock order
void Path1() {
std::lock_guard<std::mutex> lock1(mutex1_);
std::lock_guard<std::mutex> lock2(mutex2_); // Order: 1 then 2
}
void Path2() {
std::lock_guard<std::mutex> lock1(mutex1_); // Same order: 1 then 2
std::lock_guard<std::mutex> lock2(mutex2_);
}
Rule: State checks must be immediately followed by dependent action without gaps.
Anti-pattern:
// ❌ VULNERABLE: TOCTOU window
if (fileExists(path)) {
// Attacker can delete/replace file here
file = openFile(path); // May open different file
}
Required pattern:
// ✅ SECURE: Atomic check-and-use
file = openFile(path);
if (file.isValid()) {
// Use file
}
Rule: Logging must redact all Personally Identifiable Information (PII).
PII requiring redaction:
Anti-pattern:
// ❌ VULNERABLE: Logs PII
HILOG_INFO("Phone: %{public}s", phoneNumber.c_str());
HILOG_ERROR("Touch at (%{public}d, %{public}d)", x, y);
Required pattern:
// ✅ SECURE: Redact or suppress
HILOG_INFO("Phone: %{private}s", phoneNumber.c_str()); // Redacted
// Better: Don't log PII at all
HILOG_INFO("Processing phone number");
Policy: Prefer complete suppression in release builds. Use %{private} format specifier only when absolutely necessary for debugging.
Rule: Never log raw pointer addresses.
Anti-pattern:
// ❌ VULNERABLE: Leaks addresses for ASLR bypass
HILOG_INFO("Object at %p", &object);
HILOG_DEBUG("Buffer address: %{public}p", buffer);
Required pattern:
// ✅ SECURE: No address logging
HILOG_INFO("Object created");
// Use opaque IDs instead of pointers
HILOG_INFO("Object ID: %{public}d", object.id_);
Rationale: Leaking heap/stack addresses helps attackers bypass ASLR (Address Space Layout Randomization).
Rule: All privileged operations must validate caller permissions.
Anti-pattern:
// ❌ VULNERABLE: No permission check
int32_t Service::DeleteFile(const std::string& path) {
// Any caller can delete any file!
return unlink(path.c_str());
}
Required pattern:
// ✅ SECURE: Validate permissions
int32_t Service::DeleteFile(const std::string& path) {
// Verify caller has permission to access this path
if (!HasPermission(callerToken_, path, Permission::DELETE)) {
HILOG_ERROR("Permission denied for path: %{private}s", path.c_str());
return ERR_PERMISSION_DENIED;
}
// Verify path is within allowed sandbox
if (!IsPathInSandbox(path)) {
HILOG_ERROR("Path outside sandbox: %{private}s", path.c_str());
return ERR_INVALID_PATH;
}
return unlink(path.c_str());
}
Permission checks required for:
| Mistake | Consequence | Fix |
|---------|-------------|-----|
| Forgetting to check MessageParcel return values | Uninitialized data use, crashes | Always check return value |
| Validating size but not lower bound (negative) | Negative sizes pass validation | Check 0 <= size <= MAX |
| Protecting write but not read on shared container | Race condition during reads | Protect ALL access |
| Using iterator after container modification | Iterator invalidation, crashes | Hold lock during iteration |
| Logging with %{public} for PII | Information leakage | Use %{private} or don't log |
| Printing pointer addresses for debugging | ASLR bypass | Use opaque IDs |
| Skipping permission check "because it's internal" | Privilege escalation if called externally | Always validate |
Flag violations with this format:
**[HIGH SECURITY RISK] <Category>**
Location: <file_path>:<line_number>
Issue: <description>
Anti-pattern:
```cpp
<code>
Required fix:
<code>
Impact: <attacker capability if exploited>
## Real-World Impact
**Container race conditions:** Use-after-free crashes, privilege escalation through corrupted state
**IPC validation failures:** Remote code execution via deserialization exploits, memory exhaustion DoS
**PII leakage:** Privacy violations, GDPR compliance failures
**ASLR bypass:** Enables exploitation of memory corruption vulnerabilities
**Missing permission checks:** Unauthorized access to sensitive data, system modification
testing
--- name: ohos-req-value-decision description: Use after review meeting to record decision and route to next step. Triggers: 评审决策纪要, 评审结论回流, value decision, 评审接纳, 评审不接纳, 评审退回, 下次重新上会. Do NOT use for feature baseline (ohos-req-feature-baseline), review gate checks (ohos-req-review-gate), or IR generation (ohos-req-feature-to-ir). metadata: author: openharmony scope: common stage: requirements capability: value-decision version: 0.3.0 status: draft tags: - sdd - requirements
development
Use when converting an OpenHarmony requirement document, spec, or design proposal into an OpenHarmony review slide deck (需求评审 / 需求变更评审 / 设计评审 PPTX) — produces the fixed OpenHarmony-branded review-deck structure (OH logo on every page) with architecture/flow diagrams and field tables. Triggers on "需求评审PPT", "需求变更评审", "把需求文档转成评审PPT", "spec转评审PPT", "requirement/spec to review deck". NOT for arbitrary or generic slide decks unrelated to OpenHarmony requirement/design review.
testing
Use when performing the Phase 0 Step 0.5 Review Ready Gate on a 04-feature.md, especially when the user says "evaluate gate", "review readiness", "feature ready?", "should we generate IR", or when the ohos-req-intake-orchestration main session needs a structured Ready / Conditional Ready / Not Ready judgment instead of doing the check inline. Reads 01-04, runs seven fixed checks plus a conditional-items check, and returns a machine-readable JSON summary plus a human-readable table that the main session can route on. Do NOT use for feature baseline generation (ohos-req-feature-baseline), value decision recording (ohos-req-value-decision), or IR generation (ohos-req-feature-to-ir).
testing
--- name: ohos-req-requirement-intake description: Use when importing an OHOS requirement into Phase 0.1, especially for 01-requirement.md, requirement intake, background, user value, scenarios, scope, FR/NFR, affected modules, or priority. Triggers: 需求导入, 01-requirement, 需求基线, RR单号. Do NOT use for feasibility analysis (ohos-req-feasibility-analysis), architecture decision (ohos-req-arch-decision), or feature baseline (ohos-req-feature-baseline). metadata: author: openharmony scope: common