examples/review-report.md
## Security (LWS + Product) - [<severity>] <ruleId> — <file>:<line> Fix: <summary>; applied: yes/no ## Summary - <n> issues found; <m> fixed; <k> deferred (with reason)
forcedotcom/sf-skills · GitHub
Use this skill as THE specialized Lightning Web Security (LWS) validator for a Lightning Web Component bundle (`.js`, `.ts`, `.html`, `.css`, `.js-meta.xml`) — the canonical LWS/Product-Security review for LWCs, NOT a generic code-security pass. It produces either a severity-ranked finding list with code-level remediations or a SARIF 2.1.0 JSON score report keyed by the `lws-001`…`lws-023b` rule catalog. TRIGGER when the user asks to review, audit, or check an LWC component for LWS compliance issues and recommend fixes, score a component's LWS/security compliance, find dangerous DOM APIs or blocked sinks (`eval`, `Function`, `document.write`, `innerHTML`, `document.createElement('script')`, global-scope assignment to `window`/`globalThis`, unsafe URL schemes), or emit a SARIF security report. DO NOT TRIGGER for generic non-LWC security review, for building a new LWC (use experience-lwc-generate), accessibility (WCAG 2.2), RTL/i18n, or Apex/Aura/server-side review.
프로젝트 폴더에서 아래 명령어를 실행하고, 설치할 에이전트를 선택하세요.
npx skills add forcedotcom/sf-skills --skill experience-lwc-security-validate설치 명령을 직접 실행해야 적용됩니다. 지원 에이전트와 필요한 권한·라이선스는 제작자의 안내를 확인하세요.
examples/review-report.md## Security (LWS + Product) - [<severity>] <ruleId> — <file>:<line> Fix: <summary>; applied: yes/no ## Summary - <n> issues found; <m> fixed; <k> deferred (with reason)
examples/score-report.sarif.json{
"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/schemas/sarif-schema-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "experience-lwc-security-validate",
"informationUri": "https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.security_lws_intro",
"rules": [
{ "id": "lws-001", "shortDescription": { "text": "document.createProcessingInstruction" } }
]
}
},
"results": [
{
"ruleId": "lws-001",
"level": "error",
"message": { "text": "Usage of document.createProcessingInstruction creates XML injection vulnerabilities enabling XSS attacks" },
"locations": [
{
"physicalLocation": {
"artifactLocation": { "uri": "force-app/main/default/lwc/myCmp/myCmp.js" },
"region": { "startLine": 42, "startColumn": 1 }
}
}
]
}
]
}
]
}
references/lws-security-expert.md# LWSExpert
## Description
Use this tool to make LWC code secure.
## Knowledge Base
## Lightning Web Security (LWS) Analysis Assistant
The following topics, each with their own grounding, are separated by a line of dashes and a new H1 header. Treat each topic as a separate grounding.
These topics can be used to analyze any Lightning Web Components code, as well as any JavaScript or TypeScript code. The code being analyzed DOES NOT HAVE TO BE LWC CODE.
---
The following definitions are CRITICAL, DO NOT IGNORE THEM:
- "Built-in object" refers to any object that is part of the core JavaScript language.
- "Host object" refers to any object that is not a built-in object or a custom object created by the component. Host objects are defined by the "Web API" or "DOM API"
- "Web API" or "DOM API" refers to the set of objects and methods defined by the HTML and DOM standards and includes all of the following: AbortController, AbortSignal, AbsoluteOrientationSensor, AbstractRange, Accelerometer, AICreateMonitor, alert, AnalyserNode, Animation, AnimationEffect, AnimationEvent, AnimationPlaybackEvent, AnimationTimeline, AsyncDisposableStack, atob, Attr, Audio, AudioBuffer, AudioBufferSourceNode, AudioContext, AudioData, AudioDecoder, AudioDestinationNode, AudioEncoder, AudioListener, AudioNode, AudioParam, AudioParamMap, AudioProcessingEvent, AudioScheduledSourceNode, AudioSinkInfo, AudioWorklet, AudioWorkletNode, AuthenticatorAssertionResponse, AuthenticatorAttestationResponse, AuthenticatorResponse, BackgroundFetchManager, BackgroundFetchRecord, BackgroundFetchRegistration, BarcodeDetector, BarProp, BaseAudioContext, BatteryManager, BeforeInstallPromptEvent, BeforeUnloadEvent, BiquadFilterNode, Blob, BlobEvent, Bluetooth, BluetoothCharacteristicProperties, BluetoothDevice, BluetoothRemoteGATTCharacteristic, BluetoothRemoteGATTDescriptor, BluetoothRemoteGATTServer, BluetoothRemoteGATTService, BluetoothUUID, blur, BroadcastChannel, BrowserCaptureMediaStreamTrack, btoa, ByteLengthQueuingStrategy, Cache, caches, CacheStorage, cancelAnimationFrame, cancelIdleCallback, CanvasCaptureMediaStreamTrack, CanvasGradient, CanvasPattern, CanvasRenderingContext2D, CaptureController, captureEvents, CaretPosition, CDATASection, ChannelMergerNode, ChannelSplitterNode, ChapterInformation, CharacterBoundsUpdateEvent, CharacterData, chrome, clearInterval, clearTimeout, clientInformation, Clipboard, ClipboardEvent, ClipboardItem, close, closed, CloseEvent, CloseWatcher, CommandEvent, Comment, CompositionEvent, CompressionStream, confirm, console, ConstantSourceNode, ContentVisibilityAutoStateChangeEvent, ConvolverNode, CookieChangeEvent, cookieStore, CookieStore, CookieStoreManager, CountQueuingStrategy, createImageBitmap, Credential, credentialless, CredentialsContainer, CropTarget, crossOriginIsolated, crypto, Crypto, CryptoKey, CSPViolationReportBody, CSS, CSSAnimation, CSSConditionRule, CSSContainerRule, CSSCounterStyleRule, CSSFontFaceRule, CSSFontFeatureValuesRule, CSSFontPaletteValuesRule, CSSGroupingRule, CSSImageValue, CSSImportRule, CSSKeyframeRule, CSSKeyframesRule, CSSKeywordValue, CSSLayerBlockRule, CSSLayerStatementRule, CSSMarginRule, CSSMathClamp, CSSMathInvert, CSSMathMax, CSSMathMin, CSSMathNegate, CSSMathProduct, CSSMathSum, CSSMathValue, CSSMatrixComponent, CSSMediaRule, CSSNamespaceRule, CSSNestedDeclarations, CSSNumericArray, CSSNumericValue, CSSPageRule, CSSPerspective, CSSPositionTryDescriptors, CSSPositionTryRule, CSSPositionValue, CSSPropertyRule, CSSRotate, CSSRule, CSSRuleList, CSSScale, CSSScopeRule, CSSSkew, CSSSkewX, CSSSkewY, CSSStartingStyleRule, CSSStyleDeclaration, CSSStyleRule, CSSStyleSheet, CSSStyleValue, CSSSupportsRule, CSSTransformComponent, CSSTransformValue, CSSTransition, CSSTranslate, CSSUnitValue, CSSUnparsedValue, CSSVariableReferenceValue, CSSViewTransitionRule, CustomElementRegistry, customElements, CustomEvent, CustomStateSet, DataTransfer, DataTransferItem, DataTransferItemList, DecompressionStream, DelayNode, DelegatedInkTrailPresenter, DeviceMotionEvent, DeviceMotionEventAcceleration, DeviceMotionEventRotationRate, DeviceOrientationEvent, devicePixelRatio, DevicePosture, DisposableStack, document, Document, DocumentFragment, documentPictureInPicture, DocumentPictureInPicture, DocumentPictureInPictureEvent, DocumentTimeline, DocumentType, DOMError, DOMException, DOMImplementation, DOMMatrix, DOMMatrixReadOnly, DOMParser, DOMPoint, DOMPointReadOnly, DOMQuad, DOMRect, DOMRectList, DOMRectReadOnly, DOMStringList, DOMStringMap, DOMTokenList, DragEvent, DynamicsCompressorNode, EditContext, Element, ElementInternals, EncodedAudioChunk, EncodedVideoChunk, ErrorEvent, event, Event, EventCounts, EventSource, EventTarget, external, External, EyeDropper, FeaturePolicy, FederatedCredential, fence, Fence, FencedFrameConfig, fetch, fetchLater, FetchLaterResult, File, FileList, FileReader, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemHandle, FileSystemObserver, FileSystemWritableFileStream, find, Float16Array, focus, FocusEvent, FontData, FontFace, FontFaceSetLoadEvent, FormData, FormDataEvent, FragmentDirective, frameElement, frames, GainNode, Gamepad, GamepadButton, GamepadEvent, GamepadHapticActuator, Geolocation, GeolocationCoordinates, GeolocationPosition, GeolocationPositionError, getComputedStyle, getScreenDetails, getSelection, GPU, GPUAdapter, GPUAdapterInfo, GPUBindGroup, GPUBindGroupLayout, GPUBuffer, GPUBufferUsage, GPUCanvasContext, GPUColorWrite, GPUCommandBuffer, GPUCommandEncoder, GPUCompilationInfo, GPUCompilationMessage, GPUComputePassEncoder, GPUComputePipeline, GPUDevice, GPUDeviceLostInfo, GPUError, GPUExternalTexture, GPUInternalError, GPUMapMode, GPUOutOfMemoryError, GPUPipelineError, GPUPipelineLayout, GPUQuerySet, GPUQueue, GPURenderBundle, GPURenderBundleEncoder, GPURenderPassEncoder, GPURenderPipeline, GPUSampler, GPUShaderModule, GPUShaderStage, GPUSupportedFeatures, GPUSupportedLimits, GPUTexture, GPUTextureUsage, GPUTextureView, GPUUncapturedErrorEvent, GPUValidationError, GravitySensor, Gyroscope, HashChangeEvent, Headers, HID, HIDConnectionEvent, HIDDevice, HIDInputReportEvent, Highlight, HighlightRegistry, history, History, HTMLAllCollection, HTMLAnchorElement, HTMLAreaElement, HTMLAudioElement, HTMLBaseElement, HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLCollection, HTMLDataElement, HTMLDataListElement, HTMLDetailsElement, HTMLDialogElement, HTMLDirectoryElement, HTMLDivElement, HTMLDListElement, HTMLDocument, HTMLElement, HTMLEmbedElement, HTMLFencedFrameElement, HTMLFieldSetElement, HTMLFontElement, HTMLFormControlsCollection, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement, HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement, HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLLabelElement, HTMLLegendElement, HTMLLIElement, HTMLLinkElement, HTMLMapElement, HTMLMarqueeElement, HTMLMediaElement, HTMLMenuElement, HTMLMetaElement, HTMLMeterElement, HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement, HTMLOptionElement, HTMLOptionsCollection, HTMLOutputElement, HTMLParagraphElement, HTMLParamElement, HTMLPictureElement, HTMLPreElement, HTMLProgressElement, HTMLQuoteElement, HTMLScriptElement, HTMLSelectedContentElement, HTMLSelectElement, HTMLSlotElement, HTMLSourceElement, HTMLSpanElement, HTMLStyleElement, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement, HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement, HTMLTemplateElement, HTMLTextAreaElement, HTMLTimeElement, HTMLTitleElement, HTMLTrackElement, HTMLUListElement, HTMLUnknownElement, HTMLVideoElement, IDBCursor, IDBCursorWithValue, IDBDatabase, IDBFactory, IDBIndex, IDBKeyRange, IDBObjectStore, IDBOpenDBRequest, IDBRequest, IDBTransaction, IDBVersionChangeEvent, IdentityCredential, IdentityCredentialError, IdentityProvider, IdleDeadline, IdleDetector, IIRFilterNode, Image, ImageBitmap, ImageBitmapRenderingContext, ImageCapture, ImageData, ImageDecoder, ImageTrack, ImageTrackList, indexedDB, Ink, InputDeviceCapabilities, InputDeviceInfo, InputEvent, IntersectionObserver, IntersectionObserverEntry, isSecureContext, Keyboard, KeyboardEvent, KeyboardLayoutMap, KeyframeEffect, LargestContentfulPaint, LaunchParams, launchQueue, LaunchQueue, LayoutShift, LayoutShiftAttribution, LinearAccelerationSensor, localStorage, location, Location, locationbar, Lock, LockManager, matchMedia, MathMLElement, MediaCapabilities, MediaDeviceInfo, MediaDevices, MediaElementAudioSourceNode, MediaEncryptedEvent, MediaError, MediaKeyMessageEvent, MediaKeys, MediaKeySession, MediaKeyStatusMap, MediaKeySystemAccess, MediaList, MediaMetadata, MediaQueryList, MediaQueryListEvent, MediaRecorder, MediaSession, MediaSource, MediaSourceHandle, MediaStream, MediaStreamAudioDestinationNode, MediaStreamAudioSourceNode, MediaStreamEvent, MediaStreamTrack, MediaStreamTrackAudioStats, MediaStreamTrackEvent, MediaStreamTrackGenerator, MediaStreamTrackProcessor, MediaStreamTrackVideoStats, menubar, MessageChannel, MessageEvent, MessagePort, MIDIAccess, MIDIConnectionEvent, MIDIInput, MIDIInputMap, MIDIMessageEvent, MIDIOutput, MIDIOutputMap, MIDIPort, MimeType, MimeTypeArray, MouseEvent, moveBy, moveTo, MutationObserver, MutationRecord, NamedNodeMap, NavigateEvent, navigation, Navigation, NavigationActivation, NavigationCurrentEntryChangeEvent, NavigationDestination, NavigationHistoryEntry, NavigationPreloadManager, NavigationTransition, navigator, Navigator, NavigatorLogin, NavigatorManagedData, NavigatorUAData, NetworkInformation, Node, NodeFilter, NodeIterator, NodeList, Notification, NotRestoredReasonDetails, NotRestoredReasons, Observable, OfflineAudioCompletionEvent, OfflineAudioContext, offscreenBuffering, OffscreenCanvas, OffscreenCanvasRenderingContext2D, onabort, onafterprint, onanimationend, onanimationiteration, onanimationstart, onappinstalled, onauxclick, onbeforeinput, onbeforeinstallprompt, onbeforematch, onbeforeprint, onbeforetoggle, onbeforeunload, onbeforexrselect, onblur, oncancel, oncanplay, oncanplaythrough, onchange, onclick, onclose, oncommand, oncontentvisibilityautostatechange, oncontextlost, oncontextmenu, oncontextrestored, oncuechange, ondblclick, ondevicemotion, ondeviceorientation, ondeviceorientationabsolute, ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, onformdata, ongotpointercapture, onhashchange, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onlanguagechange, onload, onloadeddata, onloadedmetadata, onloadstart, onlostpointercapture, onmessage, onmessageerror, onmousedown, onmouseenter, onmouseleave, onmousemove, onmouseout, onmouseover, onmouseup, onmousewheel, onoffline, ononline, onpagehide, onpagereveal, onpageshow, onpageswap, onpause, onplay, onplaying, onpointercancel, onpointerdown, onpointerenter, onpointerleave, onpointermove, onpointerout, onpointerover, onpointerrawupdate, onpointerup, onpopstate, onprogress, onratechange, onrejectionhandled, onreset, onresize, onscroll, onscrollend, onscrollsnapchange, onscrollsnapchanging, onsearch, onsecuritypolicyviolation, onseeked, onseeking, onselect, onselectionchange, onselectstart, onslotchange, onstalled, onstorage, onsubmit, onsuspend, ontimeupdate, ontoggle, ontransitioncancel, ontransitionend, ontransitionrun, ontransitionstart, onunhandledrejection, onunload, onvolumechange, onwaiting, onwebkitanimationend, onwebkitanimationiteration, onwebkitanimationstart, onwebkittransitionend, onwheel, open, opener, Option, OrientationSensor, origin, originAgentCluster, OscillatorNode, OTPCredential, outerHeight, outerWidth, OverconstrainedError, PageRevealEvent, PageSwapEvent, PageTransitionEvent, pageXOffset, pageYOffset, PannerNode, parent, PasswordCredential, Path2D, PaymentAddress, PaymentManager, PaymentMethodChangeEvent, PaymentRequest, PaymentRequestUpdateEvent, PaymentResponse, performance, Performance, PerformanceElementTiming, PerformanceEntry, PerformanceEventTiming, PerformanceLongAnimationFrameTiming, PerformanceLongTaskTiming, PerformanceMark, PerformanceMeasure, PerformanceNavigation, PerformanceNavigationTiming, PerformanceObserver, PerformanceObserverEntryList, PerformancePaintTiming, PerformanceResourceTiming, PerformanceScriptTiming, PerformanceServerTiming, PerformanceTiming, PeriodicSyncManager, PeriodicWave, Permissions, PermissionStatus, personalbar, PictureInPictureEvent, PictureInPictureWindow, Plugin, PluginArray, PointerEvent, PopStateEvent, postMessage, Presentation, PresentationAvailability, PresentationConnection, PresentationConnectionAvailableEvent, PresentationConnectionCloseEvent, PresentationConnectionList, PresentationReceiver, PresentationRequest, PressureObserver, PressureRecord, print, ProcessingInstruction, Profiler, ProgressEvent, PromiseRejectionEvent, prompt, ProtectedAudience, PublicKeyCredential, PushManager, PushSubscription, PushSubscriptionOptions, queryLocalFonts, queueMicrotask, RadioNodeList, Range, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, RelativeOrientationSensor, releaseEvents, RemotePlayback, ReportBody, reportError, ReportingObserver, Request, requestAnimationFrame, requestIdleCallback, resizeBy, ResizeObserver, ResizeObserverEntry, ResizeObserverSize, resizeTo, Response, RestrictionTarget, RTCCertificate, RTCDataChannel, RTCDataChannelEvent, RTCDtlsTransport, RTCDTMFSender, RTCDTMFToneChangeEvent, RTCEncodedAudioFrame, RTCEncodedVideoFrame, RTCError, RTCErrorEvent, RTCIceCandidate, RTCIceTransport, RTCPeerConnection, RTCPeerConnectionIceErrorEvent, RTCPeerConnectionIceEvent, RTCRtpReceiver, RTCRtpSender, RTCRtpTransceiver, RTCSctpTransport, RTCSessionDescription, RTCStatsReport, RTCTrackEvent, scheduler, Scheduler, Scheduling, screen, Screen, ScreenDetailed, ScreenDetails, screenLeft, ScreenOrientation, screenTop, screenX, screenY, ScriptProcessorNode, scroll, scrollbars, scrollBy, ScrollTimeline, scrollTo, scrollX, scrollY, SecurityPolicyViolationEvent, Selection, self, Sensor, SensorErrorEvent, Serial, SerialPort, ServiceWorker, ServiceWorkerContainer, ServiceWorkerRegistration, sessionStorage, setInterval, setTimeout, ShadowRoot, SharedArrayBuffer, sharedStorage, SharedStorage, SharedStorageAppendMethod, SharedStorageClearMethod, SharedStorageDeleteMethod, SharedStorageModifierMethod, SharedStorageSetMethod, SharedStorageWorklet, SharedWorker, showDirectoryPicker, showOpenFilePicker, showSaveFilePicker, SnapEvent, SourceBuffer, SourceBufferList, speechSynthesis, SpeechSynthesis, SpeechSynthesisErrorEvent, SpeechSynthesisEvent, SpeechSynthesisUtterance, SpeechSynthesisVoice, StaticRange, status, statusbar, StereoPannerNode, stop, Storage, StorageBucket, StorageBucketManager, StorageEvent, StorageManager, structuredClone, styleMedia, StylePropertyMap, StylePropertyMapReadOnly, StyleSheet, StyleSheetList, SubmitEvent, Subscriber, SubtleCrypto, SuppressedError, SVGAElement, SVGAngle, SVGAnimatedAngle, SVGAnimatedBoolean, SVGAnimatedEnumeration, SVGAnimatedInteger, SVGAnimatedLength, SVGAnimatedLengthList, SVGAnimatedNumber, SVGAnimatedNumberList, SVGAnimatedPreserveAspectRatio, SVGAnimatedRect, SVGAnimatedString, SVGAnimatedTransformList, SVGAnimateElement, SVGAnimateMotionElement, SVGAnimateTransformElement, SVGAnimationElement, SVGCircleElement, SVGClipPathElement, SVGComponentTransferFunctionElement, SVGDefsElement, SVGDescElement, SVGElement, SVGEllipseElement, SVGFEBlendElement, SVGFEColorMatrixElement, SVGFEComponentTransferElement, SVGFECompositeElement, SVGFEConvolveMatrixElement, SVGFEDiffuseLightingElement, SVGFEDisplacementMapElement, SVGFEDistantLightElement, SVGFEDropShadowElement, SVGFEFloodElement, SVGFEFuncAElement, SVGFEFuncBElement, SVGFEFuncGElement, SVGFEFuncRElement, SVGFEGaussianBlurElement, SVGFEImageElement, SVGFEMergeElement, SVGFEMergeNodeElement, SVGFEMorphologyElement, SVGFEOffsetElement, SVGFEPointLightElement, SVGFESpecularLightingElement, SVGFESpotLightElement, SVGFETileElement, SVGFETurbulenceElement, SVGFilterElement, SVGForeignObjectElement, SVGGElement, SVGGeometryElement, SVGGradientElement, SVGGraphicsElement, SVGImageElement, SVGLength, SVGLengthList, SVGLinearGradientElement, SVGLineElement, SVGMarkerElement, SVGMaskElement, SVGMatrix, SVGMetadataElement, SVGMPathElement, SVGNumber, SVGNumberList, SVGPathElement, SVGPatternElement, SVGPoint, SVGPointList, SVGPolygonElement, SVGPolylineElement, SVGPreserveAspectRatio, SVGRadialGradientElement, SVGRect, SVGRectElement, SVGScriptElement, SVGSetElement, SVGStopElement, SVGStringList, SVGStyleElement, SVGSVGElement, SVGSwitchElement, SVGSymbolElement, SVGTextContentElement, SVGTextElement, SVGTextPathElement, SVGTextPositioningElement, SVGTitleElement, SVGTransform, SVGTransformList, SVGTSpanElement, SVGUnitTypes, SVGUseElement, SVGViewElement, SyncManager, TaskAttributionTiming, TaskController, TaskPriorityChangeEvent, TaskSignal, Text, TextDecoder, TextDecoderStream, TextEncoder, TextEncoderStream, TextEvent, TextFormat, TextFormatUpdateEvent, TextMetrics, TextTrack, TextTrackCue, TextTrackCueList, TextTrackList, TextUpdateEvent, TimeRanges, ToggleEvent, toolbar, top, Touch, TouchEvent, TouchList, TrackEvent, TransformStream, TransformStreamDefaultController, TransitionEvent, TreeWalker, TrustedHTML, TrustedScript, TrustedScriptURL, TrustedTypePolicy, TrustedTypePolicyFactory, trustedTypes, UIEvent, URL, URLPattern, URLSearchParams, USB, USBAlternateInterface, USBConfiguration, USBConnectionEvent, USBDevice, USBEndpoint, USBInterface, USBInTransferResult, USBIsochronousInTransferPacket, USBIsochronousInTransferResult, USBIsochronousOutTransferPacket, USBIsochronousOutTransferResult, USBOutTransferResult, UserActivation, ValidityState, VideoColorSpace, VideoDecoder, VideoEncoder, VideoFrame, VideoPlaybackQuality, ViewTimeline, ViewTransition, ViewTransitionTypeSet, VirtualKeyboard, VirtualKeyboardGeometryChangeEvent, VisibilityStateEntry, visualViewport, VisualViewport, VTTCue, WakeLock, WakeLockSentinel, WaveShaperNode, WebAssembly, WebGL2RenderingContext, WebGLActiveInfo, WebGLBuffer, WebGLContextEvent, WebGLFramebuffer, WebGLObject, WebGLProgram, WebGLQuery, WebGLRenderbuffer, WebGLRenderingContext, WebGLSampler, WebGLShader, WebGLShaderPrecisionFormat, WebGLSync, WebGLTexture, WebGLTransformFeedback, WebGLUniformLocation, WebGLVertexArrayObject, webkitCancelAnimationFrame, WebKitCSSMatrix, webkitMediaStream, WebKitMutationObserver, webkitRequestAnimationFrame, webkitRequestFileSystem, webkitResolveLocalFileSystemURL, webkitRTCPeerConnection, webkitSpeechGrammar, webkitSpeechGrammarList, webkitSpeechRecognition, webkitSpeechRecognitionError, webkitSpeechRecognitionEvent, webkitURL, WebSocket, WebSocketError, WebSocketStream, WebTransport, WebTransportBidirectionalStream, WebTransportDatagramDuplexStream, WebTransportError, WGSLLanguageFeatures, WheelEvent, window, Window, WindowControlsOverlay, WindowControlsOverlayGeometryChangeEvent, Worker, Worklet, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, XMLDocument, XMLHttpRequest, XMLHttpRequestEventTarget, XMLHttpRequestUpload, XMLSerializer, XPathEvaluator, XPathExpression, XPathResult, XRAnchor, XRAnchorSet, XRBoundedReferenceSpace, XRCamera, XRCPUDepthInformation, XRDepthInformation, XRDOMOverlayState, XRFrame, XRHand, XRHitTestResult, XRHitTestSource, XRInputSource, XRInputSourceArray, XRInputSourceEvent, XRInputSourcesChangeEvent, XRJointPose, XRJointSpace, XRLayer, XRLightEstimate, XRLightProbe, XRPose, XRRay, XRReferenceSpace, XRReferenceSpaceEvent, XRRenderState, XRRigidTransform, XRSession, XRSessionEvent, XRSpace, XRSystem, XRTransientInputHitTestResult, XRTransientInputHitTestSource, XRView, XRViewerPose, XRViewport, XRWebGLBinding, XRWebGLDepthInformation, XRWebGLLayer, XSLTProcessor
- "GlobalThisValue" is the Global Object defined in the ECMAScript specification.
- For review purposes, a "GlobalThisValue" is any of the following: `window`, `window.top`, `window.parent`, `window.frames`, `globalThis`, `self` (when `self` is at the top level of the global scope), or `this` (when `this` is at the top level of the global scope or in `eval()`).
- `document` is not a "GlobalThisValue", but the value of `defaultView` property is a "GlobalThisValue".
---
# Block Document CreateProcessingInstruction Analysis
## Code Review: Identify and Block document.createProcessingInstruction usage.
### My Job
I identify ALL usage of document.createProcessingInstruction. This API introduces XML injection and XSS vulnerabilities.
### What I Look For
Calls to document.createProcessingInstruction in all contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences and Reflection APIs.
### Why It's Critical
Creates XML injection vulnerabilities enabling XSS attacks through stylesheet injection, data URIs, and CSP bypass.
### Safe Alternative
Remove the dangerous code. If stylesheet loading is needed, use `document.createElement('link')` and append to `document.head` in JavaScript. Do not add `<link>` to any refactored markup (not allowed).
---
# Block Document Event Handler Analysis
## Code Review: Identify and Block forbidden document event handler usage.
### Rule
Flag ONLY actual event handler registrations for these THREE forbidden events:
- rejectionhandled
- securitypolicyviolation
- unhandledrejection
### Correct Usage
1. Remove all forbidden event handlers.
2. Handle errors and rejections locally within the component scope.
### Instructions
1. Scan EVERY line for these patterns
2. All contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences
3. Case-sensitive matching
4. Flag EVERY occurrence - no exceptions
5. Include the complete code context
6. Report ALL violations found
### Constraints
1. **Preserve Logic**: Maintain all other code logic. Do not remove any code that is not related to the forbidden event handlers.
2. **Complete Coverage**: Flag ALL instances of forbidden event handlers.
---
# Block Document Open
## Code Review: Identify and Block critical security issues with document.open usage.
### My Job
I examine JavaScript and TypeScript code to find ALL instances of `document.open` called with zero, one, or two arguments. These methods are inherently dangerous and represent critical security vulnerabilities that must be removed.
### What I Flag
- `document.open()` with 0 args: BLOCKED - Clears document (security risk)
- `document.open(url)` with 1 arg: BLOCKED - Opens in same window (navigation hijacking)
- `document.open(url, name)` with 2 args: BLOCKED - Opens with target in same window (security risk)
- `document.open(url, name, features)` with 3+ args: ALLOWED
I detect direct calls, bracket notation (`document['open']`), destructuring (`const {open} = document`), and variable references in all contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequencesl
### Fix Recommendations
Replace with:
- `window.open(url, "_blank", "noopener,noreferrer")` for new windows
- DOM APIs (`createElement`, `appendChild`) for content manipulation
- Navigation APIs for routing
---
# Block Document Write
## Code Review: Identify and Block unsafe document.write and document.writeln usage.
### My Job
I examine JavaScript and TypeScript code to find ALL instances of `document.write` and `document.writeln`. These methods are inherently dangerous and represent critical security vulnerabilities that must be removed.
### What I Flag
- **document.write()**: ALL uses - allows HTML injection enabling XSS attacks
- **document.writeln()**: ALL uses - identical to document.write with newline
- **Indirect calls**: Bracket notation (`document['write']`), destructuring (`const {write} = document`), aliasing
- **All contexts**: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences and Reflection APIs.
### Why Critical
These methods enable XSS attacks, can replace entire page content, block parsing, and violate LWS security policies. NO safe usage exists.
### Safe Alternatives
Use DOM APIs (`createElement`, `appendChild`), LWC templates, or `textContent` for user data.
---
# Block Direct Script Element Creation Analysis
## Code Review: Identify and Block direct script element creation.
### My Job
I detect direct script element creation and manipulation that could enable XSS attacks or CSP bypasses.
### What I Look For
- `document.createElement('script')` or `new HTMLScriptElement()`
- Script injection via innerHTML/outerHTML/insertAdjacentHTML
- Setting script.src to dynamic/untrusted URLs, blob URLs, or data URLs
- Setting script.textContent, script.text, or script.innerHTML with code
- All contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences
### Secure Alternative for Lightning Web Components
If the code contains a class that extends `LightningElement`, recommend using the platform's `loadScript` utility from `lightning/platformResourceLoader`.
### Examples
```js
// VIOLATION: Direct creation
const script = document.createElement('script');
script.src = untrustedUrl;
// VIOLATION: Setting textContent
script.textContent = userInput;
// VIOLATION: innerHTML injection
element.innerHTML = '<script>alert(1)</script>';
// VIOLATION: Blob URL
script.src = URL.createObjectURL(blob);
// SECURE (for Lightning Web Components): Use loadScript
import { loadScript } from 'lightning/platformResourceLoader';
await loadScript(this, LIBRARY_URL);
```
---
# Block eval
## Code Review: Identify and Block eval, Function, new Function and setInterval or setTimeout with a string.
### My Job
I examine Lightning Web Components and/or any JavaScript code to find all instances of eval, setInterval, setTimeout, Function, and new Function usage that represent critical security vulnerabilities.
### What I Look For
- **eval**: Any code sent to JavaScript eval function is unsafe, and should be avoided.
- **setInterval**: Any code evaluated via string argument is unsafe, and should be avoided.
- **setTimeout**: Any code evaluated via string argument is unsafe, and should be avoided.
- **Function**: Any code evaluated via string argument is unsafe, and should be avoided.
- **new Function**: Any code evaluated via string argument is unsafe, and should be avoided.
### Correct Usage
1. Occurrences of eval, Function, and new Function must be annotated with a comment warning against use.
2. Occurrences of setInterval, setTimeout that accept a string argument should be removed.
### Review Steps
1. **Identify Usage**: I check for occurrences of eval, setInterval, setTimeout, Function, and new Function in the code.
2. **Evaluate Safety**: I determine if usage is unsafe for LWS, according to the criteria above.
### Constraints
1. **Preserve Logic**: I maintain all other code logic. I do not remove any code that is not related to the issue.
---
# Block Event Properties
## Code Review: Identify and Block all event.originalTarget and event.explicitOriginalTarget usages.
### My Job
I examine JavaScript and TypeScript code to find ALL instances of forbidden event properties. I MUST report EVERY SINGLE occurrence of `event.originalTarget` and `event.explicitOriginalTarget`.
### What I Look For
**Forbidden Event Properties** (always flag):
- `event.originalTarget`
- `event.explicitOriginalTarget`
- `Event.prototype.originalTarget`
- `Event.prototype.explicitOriginalTarget`
### Why This Matters
These properties bypass Lightning Web Security's shadow DOM isolation and expose elements outside the component's security boundary.
### Review Steps
1. **Scan for direct access**: Find all `event.originalTarget` and `event.explicitOriginalTarget` usage
2. **Check prototype modifications**: Find modifications to Event.prototype
3. **Flag all instances**: Every occurrence is a violation
### Output Format
For each issue I find:
- **Suggested Action**: Use `event.target` or `event.currentTarget` instead
### Constraints
1. **Complete coverage**: Return EVERY instance found in the code
### Important Notes
- There are NO exceptions for these forbidden properties
- ALL instances must be flagged regardless of context
---
# Block Fullscreen API
## Code Review: Identify and Block requestFullscreen and vendor prefixed versions usage.
### My Job
I examine Lightning Web Components and/or any JavaScript or TypeScript code to find all instances of requestFullscreen() method invocations. Only requestFullscreen and its vendor-prefixed variants are violations.
### What I Look For
#### Critical Security Issues - Fullscreen API Invocations
**Methods** (always flag):
- `requestFullscreen()` - Standard method
- `webkitRequestFullscreen()` - WebKit prefix
- `mozRequestFullScreen()` - Mozilla prefix (capital 'S' in 'Screen')
- `msRequestFullscreen()` - Microsoft prefix
### Key Considerations
- **Fullscreen API**: Any usage of Fullscreen API method - requestFullscreen as well as vendor prefixed versions - is unsafe and can be exploited for phishing attacks by hiding browser security indicators.
- **All variants**: This includes all browser-prefixed versions (webkit, moz) and all access patterns (direct, dynamic, stored references).
- **Case sensitivity**: Pay special attention to mozRequestFullScreen (capital 'S' in 'Screen') vs other variants.
- **String property access**: Pay special attention to string properties that contain the word 'fullscreen' as well as the word 'screen', it can act as a backdoor entry point for phishing attacks.
### Correct Usage
1. Remove all requestFullscreen and vendor prefixed versions usage from Lightning Web Components and/or any JavaScript code.
2. Do not implement fullscreen functionality due to security risks.
### Review Steps
1. All occurrences of requestFullscreen is a violation.
### Constraints
1. **Preserve Logic**: Maintain all other code logic. Do not remove any code that is not related to the requestFullscreen and vendor prefixed versions.
---
# Block Global Object Property Assignment Analysis
## Code Review: Identify and Block all direct property assignments to global objects.
**CRITICAL PREREQUISITE:**
- ONLY analyze files that import from 'lwc'
- If a file does NOT import from 'lwc', DO NOT flag ANY issues in that file
- **IMPORTANT:** If a file has NO import statements at all, it should be skipped entirely
- **WARNING:** Even if you find obvious GlobalThisValue assignments like `globalThis.property = value`, you MUST ignore them if there's no LightningElement import
- This rule applies to the ENTIRE file - if no LightningElement import, skip the file entirely
### Review Steps
1. **STEP 1 - Import Check (MANDATORY):**
- Search the entire file for any import declarations whose with clause is 'lwc'
**DECISION POINT:**
- If an import is found → Continue to Step 2
- If NO import declaration whose with clause is 'lwc' are found → Return empty list (no issues). DO NOT CONTINUE TO STEP 2.
2. **STEP 2 - Global Object Analysis (only if Step 1 passed):**
- Find all JavaScript code that directly assigns properties to global objects. Look for patterns like:
- `globalThis.propertyName = value`
- `window.propertyName = value`
- `window.top.propertyName = value`
- `window.parent.propertyName = value`
- `window.frames.propertyName = value`
- `document.defaultView.propertyName = value`
- `self.propertyName = value` (when self refers to the global object)
- `this.propertyName = value` (when this refers to the global object in global scope, or at the top level)
3. Do NOT flag:
- Property access (reading): `const x = window.location`
- Local assignments: `function foo(window) { window.localVar = 1 }`
- Method calls: `window.alert('hello')`
- Host objects (like document etc.) EXCEPT when they are used as global object references
4. IMPORTANT:
- NEVER flag Built-in objects (like Set, Map, Array, etc.)
- NEVER flag Host objects (like document etc.) EXCEPT when they are used as global object references
- Global object references that should be flagged: globalThis, window, window.top, window.parent, window.frames, document.defaultView, self (global), this (global)
### Examples
**Examples of what to FLAG:**
```javascript
globalThis.myVar = 'hello';
window.config = { debug: true };
window.top.config = { debug: true };
window.parent.config = { debug: true };
window.frames.config = { debug: true };
self.data = [];
this.globalFunction = function () {};
document.defaultView.property = value;
globalThis.foo += 1;
window.bar -= 5;
```
**Examples of what to IGNORE:**
```javascript
const x = window.location; // reading, not assigning
function foo(window) {
window.local = 1;
} // local parameter
window.alert('hello'); // method call, not assignment
const config = window.config; // reading
document.cookie = 'foo=bar'; // DO NOT FLAG - document is not in the flagged list
localStorage.setItem('key', 'value'); // DO NOT FLAG - localStorage is not in the flagged list
document.foo = 1; // DO NOT FLAG - document is not in the flagged list
```
When reviewing code, include ALL VIOLATIONS. Do not omit any.
### Constraints
1. **LightningElement Import Required**: Only analyze files that import LightningElement
2. **Preserve Logic**: Maintain all other code logic.
3. ONLY report issues that are related to the instructions.
4. Properties of other objects are not considered "global objects" references.
5. Violations of the rules are considered security issues.
### Final Validation
Before returning any issues, ask yourself:
1. Does this file import LightningElement? (Check for import statements)
2. If NO → Return empty list
3. If YES → Return the issues found
**Remember:** No LightningElement import = No issues to report, regardless of what global object assignments you find.
---
# Block HTML Body Element Event Analysis
## Code Review: Identify and Block use of document.body event handlers that leak sensitive information
### My Job
I find document.body event handler usage that creates security vulnerabilities by exposing promise rejections, storage events, navigation state, and enabling user tracking.
### What I Detect
- `document.body.addEventListener(...)` and `document.body.oneventname = ...` assignments
- Destructured references: `const { body } = document;` then `body.addEventListener` or `body.oneventname`
- Bracket notation: `document.body['on' + var]` or `body[eventName]`
- Unicode escapes: `document.body['\u006f\u006e...']`
- Reflect patterns: `Reflect.set(document.body, 'onevent', ...)` or `Reflect.apply(document.body.addEventListener, ...)`
- String concatenation for event names
### What I Report
I flag only the **actual handler assignment line**, not intermediate variable construction. I report ALL occurrences case-sensitively.
---
# Block Nonce Access Analysis
## Code Review: Identify and Block nonce value access violations (CSP enforcement)
### My Job
I identify ALL attempts to access nonce values on HTMLElement/SVGElement objects. Nonce access enables CSP bypass attacks.
### Core Rule
Nonces are cryptographic tokens for Content-Security-Policy and must NEVER be readable from client-side JavaScript.
### What I Look For
- **Direct access**: `element.nonce`, `element['nonce']`
- **getAttribute methods**: `.getAttribute('nonce')`, `.getAttributeNode('nonce')`
- **Selectors**: `querySelector('[nonce]')`, `querySelectorAll('script[nonce]')`
- **Variable-based**: `element[prop]`, `getAttribute(attrName)`, string concat/templates
- **Storage**: `localStorage/sessionStorage.setItem()` with nonce values
- **Setting**: `element.nonce = value`, `setAttribute('nonce', value)`
- **Loops**: `forEach`, `map`, `for...of` accessing nonce
- **Destructuring**: `const { nonce } = element`
- **Conditionals**: `if (element.nonce)`, `element.nonce || default`
### Why It Matters
Stolen nonces allow attackers to inject unauthorized scripts that bypass CSP, enabling XSS attacks.
### Correct Approach
If the code contains a class that extends `LightningElement`, use `loadScript`/`loadStyle` from `lightning/platformResourceLoader`. Never access, store, or transmit nonce values.
---
# Block UIEvent Range Parent Analysis
## Code Review: Identify and Block UIEvent Range Parent Access
### My Job
I find all instances where code accesses the `rangeParent` property from event objects. This includes direct access (event.rangeParent), chained access (event.target.rangeParent), destructuring, and obfuscated patterns using unicode escapes, bracket notation, or Reflect APIs.
### Fix
Replace with event.target or event.currentTarget instead.
---
# Block XSLTProcessor Analysis
## Code Review: Identify and Block all XSLTProcessor API usage.
### My Job
I find ALL instances of `XSLTProcessor`, `transformToFragment`, and `transformToDocument`. These APIs enable XSS attacks and bypass security controls.
### What I Look For
- `new XSLTProcessor()` - direct instantiation
- `window.XSLTProcessor` or `const P = XSLTProcessor` - indirect references
- `Reflect.construct(XSLTProcessor, [])` - reflection-based instantiation
- `transformToFragment()` and `transformToDocument()` - transformation methods
- `processor['transformToFragment']` - bracket notation
- `Reflect.apply()`, `.apply()`, `.call()`, `.bind()` - reflection-based method calls
### Why This Matters
XSLT transformations can generate `<script>` tags, event handlers, and bypass CSP. There is NO safe usage.
### Safe Alternatives
1. If the code contains a class that extends `LightningElement`, use LWC templates with data binding
2. Process XML on server-side with Apex
3. Use JSON instead of XML
4. Use DOM APIs (`createElement`, `appendChild`) with proper escaping
### Output Format
---
# Block Context Vulnerability Access Analysis
## Code Review: Identify and Block context vulnerability attacks.
### My Job
I identify security vulnerabilities where **imported framework classes** are exploited through context manipulation: bind(), call(), apply(), Reflect methods, prototype manipulation, and framework element access.
**CRITICAL**: Imported modules expose framework internals. Static resources via loadScript() are safe.
### What I Look For
1. **Method Context Manipulation**: .call(), .apply(), .bind(), Reflect.apply() on imported methods with external context
2. **Crafted Fake Context**: Objects mimicking framework structures passed to framework methods
3. **Component Extension**: Extending imported framework components to access inherited internals
4. **Prototype Manipulation**: **lookupSetter**(), **lookupGetter**(), Object.getPrototypeOf(), Object.setPrototypeOf()
5. **Internal Property Access**: .helper, .context, .owner, .navService on DOM elements/components
6. **Hierarchy Traversal**: getOwner(), getContext() calls or loops traversing object hierarchies
7. **Dynamic Creation with Exploited Context**: Using stolen contexts for component creation
8. **Complex Invocation Chains**: Function.prototype.call.apply() or Function.prototype.apply.call()
9. **All contexts**: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences
### What I Ignore
- Standard LWC lifecycle methods
- Event handlers with proper this binding within same component
- Built-in JavaScript methods without external context manipulation
- Code loaded via loadScript() from static resources
### Attack Patterns
**CustomEvent Context Claiming**
```javascript
// BAD: Intercepting framework context via CustomEvent
let evt = new CustomEvent(frameworkEventName, {
detail: {
callback: function (ctx) {
while (true) {
let root = ctx.getOwner();
if (root === ctx) break;
ctx = root;
}
ctx.helper.someMethod.call({ initService: { property: document } }, data);
},
},
});
```
**Component Extension + Prototype**
```javascript
// BAD: Extending imported component with prototype manipulation
import ImportedComponent from 'framework/componentName';
export default class extends ImportedComponent {
renderedCallback() {
this.__lookupSetter__('prop').call(fakeContext, payload);
}
}
```
**Framework Access + Traversal**
```javascript
// BAD: Accessing internal elements and traversing context
let element = document.querySelector('framework-internal-element');
let ctx = element.internalService.context;
while (ctx.getOwner() !== ctx) ctx = ctx.getOwner();
```
### Correct Usage
1. Never access internal properties (.helper, .context, .owner, .navService)
2. Never traverse hierarchies (getOwner(), getContext())
3. Only query within template: this.template.querySelector()
4. Never extend imported framework components
5. Never use context manipulation on imported objects with external contexts
---
# Block Insecure HTML Injection
## Code Review: Identify and Block insecure HTML injection through DOM sinks that could lead to security vulnerabilities.
### My Job
I examine Lightning Web Components and/or any JavaScript or TypeScript code for insecure HTML injection patterns through DOM sinks. I focus on any usage where untrusted or dynamically constructed HTML content is assigned to DOM manipulation methods, regardless of whether it's on regular elements, shadowRoot, or document objects.
### What I Look For
- **innerHTML assignments**: Direct assignment of untrusted content to innerHTML (on any element, shadowRoot, or document)
- **outerHTML assignments**: Direct assignment of untrusted content to outerHTML
- **insertAdjacentHTML calls**: Using insertAdjacentHTML with untrusted content
- **setHTML/setHTMLUnsafe calls**: Using these methods with untrusted content
- **Dangerous content patterns**:
- Strings containing iframe elements with srcdoc attributes
- Strings containing script elements
- Dynamic HTML construction from variables
- **textContent with HTML**: Setting textContent to content that contains HTML markup
- **Any pattern where user input or external data is directly inserted into DOM sinks without proper sanitization**
### What I Ignore
- Safe DOM methods like createElement, appendChild, removeChild
- Proper use of textContent with plain text (no HTML)
- LWC template rendering and data binding
- Standard Lightning component usage
- Comments in code (I analyze the actual code logic, not comments)
### Security Risks
DOM sinks that accept HTML content are dangerous because:
1. **XSS vulnerabilities**: Malicious scripts can be injected through HTML content
2. **DOM manipulation attacks**: Attackers can modify the DOM structure
3. **Data exfiltration**: Sensitive data can be accessed through injected scripts
4. **Session hijacking**: Attackers can steal authentication tokens
5. **iframe/script injection**: Particularly dangerous patterns that bypass some security measures
### Safe Alternatives
Instead of unsafe DOM sink assignments, recommend:
- Use createElement() and appendChild() for safe DOM manipulation
- Use textContent for plain text (never HTML)
- Use LWC's templating system for dynamic content
- Implement proper input validation and sanitization
- Use Trusted Types when available
### Example of Unsafe Code
```js
export default class UnsafeComponent extends LightningElement {
connectedCallback() {
const userInput = this.getUserInput(); // Could contain malicious HTML
// All of these are UNSAFE:
this.template.querySelector('div').innerHTML = userInput;
this.template.querySelector('div').shadowRoot.innerHTML = userInput;
const blob = new Blob(['alert(document.cookie)'], { type: 'application/json' });
const math = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'x');
math.setHTMLUnsafe(
`<style><!--</style><img src="--><mi><iframe srcdoc='<script src=${URL.createObjectURL(blob)}></script>'></iframe>"/>
);
}
}
```
### Example of Safe Code
```js
export default class SafeComponent extends LightningElement {
connectedCallback() {
const userInput = this.getUserInput();
// SAFE approaches:
const div = this.template.querySelector('div');
const textNode = document.createTextNode(userInput);
div.appendChild(textNode);
// Or use textContent for plain text
div.textContent = userInput;
}
}
```
---
# Restrict Document ExecCommand Analysis
## Code Review: Flag and Restrict Dangerous document.execCommand Usage
### My Job
I scan for dangerous `document.execCommand` usage that enables HTML injection or unauthorized data access, specifically `insertHTML` and `selectAll` commands.
### What I Flag
I flag ONLY `insertHTML` and `selectAll` commands. All other commands are safe and ignored.
**Dangerous Commands:**
- `insertHTML` - Enables HTML injection and XSS attacks
- `selectAll` - Can expose sensitive content via clipboard manipulation
**Detection Patterns:**
- Direct calls: `document.execCommand('insertHTML', ...)`
- Variables: `document.execCommand(cmdVar, ...)` where cmdVar could be dangerous
- String concatenation: `'insert' + 'HTML'`
- Bracket notation: `document['execCommand']('selectAll')`
- Unicode escape sequences
### Secure Alternatives
**For insertHTML:**
- Use Selection API with `Range.insertNode()` and `document.createElement()`
- Use `textContent` for text insertion
- Sanitize HTML if HTML insertion is required
**For selectAll:**
- Use `window.getSelection().selectAllChildren(element)`
- Use `Range.selectNodeContents(element)`
- Use modern Clipboard API: `navigator.clipboard.writeText()`
---
# Avoid Map Object Misuse
## Code Review: Prevent Map and Set objects misuse.
### My Job
I identify Map and Set misuse in any Lightning Web Component code, JavaScript code, or TypeScript code.
### What I Look For
#### Direct Property Access/Assignment (CRITICAL)
- Using bracket notation: `map[key]` or `set[index]`
- Assigning with brackets: `map[key] = value` or `set[index] = value`
- **Why**: Map/Set use internal data structures. Direct property access bypasses their API.
- **Fix**: Use `map.set(key, value)`, `map.get(key)`, `set.add(value)`, `set.has(value)`
#### Serialization Issues
- Using `JSON.stringify()` on Map or Set directly
- Passing Map/Set in decorators (e.g., `@wire`, `@track`)
- Sending Map/Set in event payloads or to child components
- **Why**: Map/Set cannot be serialized.
- **Fix**: Convert to serializable format - `Object.fromEntries(map)`, `Array.from(set)`
#### Prototype Modification (CRITICAL)
- Adding properties to `Map.prototype` or `Set.prototype`
- **Why**: Extremely dangerous, affects all instances globally.
- **Fix**: Create custom classes that extend Map/Set
### What I Ignore
- DOM API usage
- Code unrelated to Map/Set misuse
---
# Avoid Mutating Unknown Objects Analysis
## Code Review: Prevent mutation of objects that don't belong to the component.
### My Job
I identify instances where code mutates objects that don't belong to the component. This includes modifying objects from external sources (events, parameters, API responses, @api properties), Built-In Objects, Host Objects, objects from inherited methods, or adding non-standard properties to DOM elements (which should use dataset API).
### What I Look For
- **Event object mutations** (e.g., `event.detail.value = 'x'`, `event.target.customProp = true`)
- **Parameter mutations** (e.g., `processConfig(config) { config.newProp = 'value'; }`)
- **API response mutations** (e.g., `wireData.processed = true`, `response.items.customField = 123`)
- **Mutations to properties received via @api** (e.g., `this.recordData.processed = true` where recordData is from @api)
- **Non-standard properties on DOM elements** (e.g., `element.customProp = 123` - use dataset API instead)
- **Tracked property mutations** (e.g., mutating wire data or external objects after storing in @track)
- **Prototype/Host Object mutations** (e.g., `Array.prototype.custom = fn`, `document.foo = 'x'`)
- **Mutations to objects from inherited methods** (methods not defined in this component)
### What I Ignore
- Objects created and owned by this component (not received from external sources)
- Standard DOM operations (e.g., createElement, appendChild, querySelector, innerHTML, textContent, classList)
- Standard event handling (e.g., addEventListener, removeEventListener)
- Mutations to cloned/copied objects (e.g., `const local = { ...external }; local.prop = 'x';`)
### Correct Approach
- **Clone before modifying** (e.g., `const local = { ...external };` or `structuredClone(data)`)
- **Return new objects** instead of mutating parameters
- **Use dataset API for DOM metadata** (e.g., `element.dataset.custom = '123'` or `element.setAttribute('data-custom', '123')`)
---
# Restrict Iframe Security Analysis
## Code Review: Flag and Restrict critical security issues with iframe usage.
### My Job
I examine code to detect insecure iframe usage that leads to XSS or mXSS attacks. I **BLOCK all srcdoc usage** (bypasses CSP) and **RESTRICT src to http/https only** (block javascript:, data:, blob:, file:, vbscript:, ftp:, etc.).
### Patterns I Detect
```js
// BLOCKED: Any srcdoc usage
element.innerHTML = '<iframe srcdoc="<script>alert(1)</script>"></iframe>';
iframe.setAttribute('srcdoc', '<html>...</html>');
// BLOCKED: Dangerous protocols (not http/https)
iframe.src = 'javascript:alert(1)';
iframe.src = 'data:text/html,<script>alert(1)</script>';
iframe.src = URL.createObjectURL(blob);
iframe.src = 'vbscript:msgbox(1)';
iframe.src = 'file:///etc/passwd';
// BLOCKED: mXSS attacks (MathML/SVG/CDATA + srcdoc)
math.setHTMLUnsafe(`<style><!--</style><img src="--><mi><iframe srcdoc='...'></iframe>"/>`);
div.innerHTML = `<svg><desc><iframe srcdoc='<script>...</script>'></iframe></desc></svg>`;
// BLOCKED: Obfuscated protocols
iframe.src = '\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074:alert(1)';
iframe.src = 'java' + 'script:' + 'alert(1)';
// ALLOWED: Only http/https
iframe.src = 'https://trusted-domain.com/content';
div.innerHTML = '<iframe src="https://example.com"></iframe>';
```
### How I Work
- I scan for srcdoc in strings, setAttribute calls, template literals, and DOM sinks
- I scan iframe src for any protocol except http/https (including obfuscated variants)
- I detect mXSS contexts (MathML, SVG, CDATA) combined with iframe srcdoc
- I track variables, template literals, string concatenation, and unicode escape sequence patterns
- I return detailed issue reports or an empty list if code is safe
---
# Restrict Trusted Type Policy Analysis
## Code Review: Flag and Restrict use of forbidden Trusted Type Policy names.
### My Job
I examine Lightning Web Components and/or any JavaScript code to find all instances of `trustedTypes.createPolicy()` where the first argument (the name) is one of the forbidden names.
### What I Look For
Policy names that match any of these forbidden names must be renamed:
- **'default'**
- **'' (empty string)**
- **'lwsInternal'**
- **'trusted'**
### Correct Usage
1. Policy names must not match any of the forbidden names.
2. This applies in all situations, including when the name is a variable, simple string literal, built with string concatenation, computed via unicode escapes, or accessed via Reflect APIs.
3. The function call may be assigned to a variable (const, let, var) or used directly.
### Review Steps
1. **Identify Usage**: I check for all occurrences of `trustedTypes.createPolicy()` in the code.
2. **Evaluate Name**: I trace the first argument to determine its value, accounting for variables, string concatenation, array/object access, function returns, and Reflect APIs.
3. **Decode Unicode escape sequences** to determine intention.
4. **Match Against Forbidden Names**: I check if the resolved value matches any forbidden name.
### Constraints
1. **Preserve Logic**: I maintain all other code logic. I do not review the content of the policy (the second argument).
2. **Focus on Name**: I only review the policy name parameter.
---
# Restrict URL.createObjectURL Analysis
## Code Review: Flag and Restrict URL.createObjectURL usage.
### My Job
I examine code to identify uses of `URL.createObjectURL()` with restricted or unsupported MIME types. This API can be exploited to create malicious object URLs that bypass security controls when used with certain MIME types.
### Restricted MIME Types (Always Flag)
- `text/javascript` - CRITICAL: Blocked completely (if the code contains a class that extends `LightningElement`, use `loadScript` from `lightning/platformResourceLoader`)
- `text/html` - WARNING: Must be scanned for malicious content (script tags, XSS)
- `image/svg+xml` - WARNING: Can contain embedded JavaScript
- `text/xml` - WARNING: Must be scanned for malicious payloads
- Empty/undefined MIME types - Treated as text/plain but interpreted differently by browsers
### Where to Look
`URL.createObjectURL()` calls, Blob/File creation with `type` property, variable-based MIME types, string concatenation/template literals building MIME types.
### Output Format
- **Type**: "URL.createObjectURL with restricted/unsupported MIME type"
- **Severity**: "Critical" (text/javascript, empty types) or "Warning" (text/html, svg, xml)
- **Location**: Line and column numbers
- **MIME Type**: The specific restricted type
- **Code**: Specific line
- **Description**: Why it's restricted and security risks
- **Intent Analysis**: What developer intended
- **Suggested Action**: Use safe MIME types (image/png, video/mp4, application/pdf) or proper APIs (loadScript, DOMPurify)
### Key Rules
1. Evaluate all contexts, variable names, string literals, string concatenations, computed values, and unicode escapes
2. Flag ALL instances of restricted MIME types - no exceptions
3. Return empty array if no issues
4. Don't flag safe MIME types (image/_, video/_, audio/\*, application/pdf)
5. Detect obfuscation: `'text/' + 'javascript'`, template literals, conditional assignments
---
# Restrict URL Schemes Analysis
## Code Review: Flag and Restrict disallowed URL schemes.
### My Job
Find all URLs using disallowed schemes. ONLY allowed: "http", "https", "about:blank". All others are critical security vulnerabilities.
### Disallowed Schemes (Always Flag)
- `javascript:`, `vbscript:` - Code execution, XSS attacks
- `data:`, `blob:` - Bypasses CSP, executable content
- `file:` - File system access
- `ftp:`, `ws:` - Insecure protocols
- `tel:`, `mailto:` - Potentially exploitable
- Any custom/non-standard schemes
### Where to Look
HTML attributes (href, src, action), JavaScript strings/template literals, URL constructors, window.location/open, element.setAttribute, fetch/XHR URLs.
### Output Format
- **Type**: "Disallowed URL Scheme: [scheme]"
- **Location**: Line and column numbers
- **Code**: Specific line
- **Description**: Why it's a vulnerability
- **Intent Analysis**: What developer intended
- **Suggested Action**: Safe alternative using allowed schemes
### Key Rules
1. Case insensitive detection (JavaScript:, JAVASCRIPT:)
2. Flag ALL instances - no exceptions
3. Return empty array if no issues
4. Check both HTML templates and JavaScript
5. Detect obfuscation like `'java' + 'script:'`
6. about:blank ONLY as literal "about:blank"
---
# Restrict SVGAnimateElement Attributes Analysis
## Code Review: Flag and Restrict use of URL values with SVGAnimateElements
### My Job
I identify when SVGAnimateElement's `to`, `from`, or `values` attributes contain URL values like `url(...)`. This is INFORMATIONAL only - LWS automatically sanitizes these values for security.
### What to Flag
Flag ONLY when these patterns exist on SVGAnimateElement:
- `setAttribute('to', ...)` or `setAttribute('from', ...)` or `setAttribute('values', ...)` where the value contains `url(...)`
- Variable or template literal values that resolve to strings containing `url(...)`
- Return **empty array** if no URL patterns found in these attributes
### Critical Rules
1. **ONLY flag SVGAnimateElement**: The element must be created with `createElementNS('http://www.w3.org/2000/svg', 'animate')`
2. **ONLY these 3 attributes**: `to`, `from`, `values` - ignore all other attributes
3. **URL pattern required**: The attribute value must contain `url(...)` pattern
4. **Empty array if none found**: Return [] if no matches
### Examples to Flag
```javascript
const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
animate.setAttribute('to', 'url(#gradient)'); // FLAG: URL in 'to'
animate.setAttribute('from', 'url(#start)'); // FLAG: URL in 'from'
animate.setAttribute('values', 'url(#a); url(#b)'); // FLAG: URLs in 'values'
```
### Examples NOT to Flag
```javascript
const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
animate.setAttribute('dur', '3s'); // DON'T FLAG: no URL
animate.setAttribute('to', '#FF0000'); // DON'T FLAG: no url() pattern
```
---
_Generated from: src/experts/lws/lwsExpert.ts_
references/security-analysis.md### Document.createProcessingInstruction
#### How to Find the Issue
Flag ALL usage of `document.createProcessingInstruction` including:
- Direct calls, bracket notation, destructuring
- Variable-based or dynamically constructed method names
- String concatenation or template literals creating the method name
- All contexts: Loops, conditionals, event handlers, async callbacks, hidden by unicode escape sequences and Reflection APIs
#### How to report the Issue
**RuleId: lws-001**
**level: error**
**message: Usage of document.createProcessingInstruction creates XML injection vulnerabilities enabling XSS attacks**
---
### Document Event Handlers
#### How to Find the Issue
Flag ONLY actual event handler registrations for these THREE forbidden events (case-sensitive):
- `rejectionhandled`
- `securitypolicyviolation`
- `unhandledrejection`
Include all contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences.
#### How to report the Issue
**RuleId: lws-002**
**level: error**
**message: Usage of forbidden document event handler ({eventName}) exposes sensitive information**
---
### Document.open
#### How to Find the Issue
Flag `document.open` based on argument count:
- `document.open()` with 0 args: **BLOCKED** - Clears document (security risk)
- `document.open(url)` with 1 arg: **BLOCKED** - Opens in same window (navigation hijacking)
- `document.open(url, name)` with 2 args: **BLOCKED** - Opens with target in same window (security risk)
- `document.open(url, name, features)` with 3+ args: **ALLOWED**
Include indirect access patterns: bracket notation (`document['open']`), destructuring (`const {open} = document`), and variable references in all contexts.
#### How to report the Issue
**RuleId: lws-003**
**level: error**
**message: Usage of document.open with {argCount} arguments is a security risk**
---
### Document.write/writeln
#### How to Find the Issue
Flag ALL uses of `document.write()` and `document.writeln()`:
- **document.write()**: ALL uses - allows HTML injection enabling XSS attacks
- **document.writeln()**: ALL uses - identical to document.write with newline
- **Indirect calls**: Bracket notation (`document['write']`), destructuring (`const {write} = document`), aliasing
- **All contexts**: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences and Reflection APIs
#### How to report the Issue
**RuleId: lws-004**
**level: error**
**message: Usage of document.write/writeln enables XSS attacks and violates LWS security policies**
---
### Eval and Dynamic Code Execution
#### How to Find the Issue
Flag these patterns:
- **eval**: ANY usage - code sent to JavaScript eval function is unsafe
- **Function** / **new Function**: ANY usage - code evaluated via string argument is unsafe
- **setInterval** / **setTimeout**: ONLY with string arguments (function arguments are safe)
#### How to report the Issue
**RuleId: lws-005**
**level: error**
**message: Usage of {functionName} enables arbitrary code execution**
---
### Event Properties
#### How to Find the Issue
Flag ALL usage of:
- `event.originalTarget`
- `event.explicitOriginalTarget`
- `Event.prototype.originalTarget`
- `Event.prototype.explicitOriginalTarget`
These properties bypass Lightning Web Security's shadow DOM isolation and expose elements outside the component's security boundary.
#### How to report the Issue
**RuleId: lws-006**
**level: error**
**message: Access to {propertyName} bypasses shadow DOM isolation**
---
### Fullscreen API
#### How to Find the Issue
Flag ALL usage of:
- `requestFullscreen()` - Standard method
- `webkitRequestFullscreen()` - WebKit prefix
- `mozRequestFullScreen()` - Mozilla prefix (note capital 'S' in 'Screen')
- `msRequestFullscreen()` - Microsoft prefix
- String property access containing 'fullscreen' or 'screen'
- All browser-prefixed versions and all access patterns (direct, dynamic, stored references)
#### How to report the Issue
**RuleId: lws-007**
**level: error**
**message: Fullscreen API usage can be exploited for phishing attacks**
---
### Global Object Property Assignment
#### How to Find the Issue
**CRITICAL PREREQUISITE**: Only analyze files that import from 'lwc'. If no 'lwc' import exists, return empty list. If a file has NO import statements at all, skip it entirely.
Flag property assignments to: `globalThis`, `window`, `window.top`, `window.parent`, `window.frames`, `document.defaultView`, `self`, or `this` (in global scope).
**Examples to Flag**:
- `globalThis.myVar = 'hello'`
- `window.config = { debug: true }`
- `window.top.config = { debug: true }`
- `self.data = []`
- `document.defaultView.property = value`
**Do NOT Flag**:
- Property reads: `const x = window.location`
- Local scope assignments: `function foo(window) { window.local = 1 }`
- Method calls: `window.alert('hello')`
- Document properties: `document.cookie = 'foo=bar'` (document is not in the flagged list)
#### How to report the Issue
**RuleId: lws-008**
**level: error**
**message: Direct property assignment to global object {objectName} pollutes global namespace**
---
### HTML Body Element Events
#### How to Find the Issue
Flag document.body event handler usage that creates security vulnerabilities:
- `document.body.addEventListener(...)` and `document.body.oneventname = ...` assignments
- Destructured references: `const { body } = document;` then `body.addEventListener` or `body.oneventname`
- Bracket notation: `document.body['on' + var]` or `body[eventName]`
- Unicode escapes: `document.body['\u006f\u006e...']`
- Reflect patterns: `Reflect.set(document.body, 'onevent', ...)` or `Reflect.apply(document.body.addEventListener, ...)`
- String concatenation for event names
Flag only the actual handler assignment line, not intermediate variable construction. Report ALL occurrences case-sensitively.
#### How to report the Issue
**RuleId: lws-009**
**level: error**
**message: document.body event handler usage leaks sensitive information**
---
### Nonce Access
#### How to Find the Issue
Flag ALL nonce access on HTMLElement/SVGElement objects. Nonce access enables CSP bypass attacks.
**What to Look For**:
- **Direct access**: `element.nonce`, `element['nonce']`
- **getAttribute methods**: `.getAttribute('nonce')`, `.getAttributeNode('nonce')`
- **Selectors**: `querySelector('[nonce]')`, `querySelectorAll('script[nonce]')`
- **Variable-based**: `element[prop]`, `getAttribute(attrName)`, string concat/templates
- **Storage**: `localStorage/sessionStorage.setItem()` with nonce values
- **Setting**: `element.nonce = value`, `setAttribute('nonce', value)`
- **Loops**: `forEach`, `map`, `for...of` accessing nonce
- **Destructuring**: `const { nonce } = element`
- **Conditionals**: `if (element.nonce)`, `element.nonce || default`
#### How to report the Issue
**RuleId: lws-010**
**level: error**
**message: Nonce access enables CSP bypass attacks**
---
### UIEvent Range Parent
#### How to Find the Issue
Flag ANY access to `rangeParent` property from event objects including:
- Direct access: `event.rangeParent`
- Chained access: `event.target.rangeParent`
- Destructuring, obfuscated patterns using unicode escapes, bracket notation, or Reflect APIs
#### How to report the Issue
**RuleId: lws-011**
**level: error**
**message: Access to rangeParent property is forbidden**
---
### XSLT Processor
#### How to Find the Issue
Flag ALL usage of:
- `new XSLTProcessor()` - direct instantiation
- `window.XSLTProcessor` or `const P = XSLTProcessor` - indirect references
- `Reflect.construct(XSLTProcessor, [])` - reflection-based instantiation
- `transformToFragment()` and `transformToDocument()` - transformation methods
- `processor['transformToFragment']` - bracket notation
- `Reflect.apply()`, `.apply()`, `.call()`, `.bind()` - reflection-based method calls
XSLT transformations can generate `<script>` tags, event handlers, and bypass CSP. There is NO safe usage.
#### How to report the Issue
**RuleId: lws-012**
**level: error**
**message: XSLTProcessor usage enables XSS attacks and CSP bypass**
---
### Context Vulnerability
#### How to Find the Issue
Flag security vulnerabilities where **imported framework classes** are exploited through context manipulation.
**CRITICAL**: Imported modules expose framework internals. Static resources via loadScript() are safe.
**Patterns to Flag**:
1. **Method Context Manipulation**: `.call()`, `.apply()`, `.bind()`, `Reflect.apply()` on imported methods with external context
2. **Crafted Fake Context**: Objects mimicking framework structures passed to framework methods
3. **Component Extension**: Extending imported framework components to access inherited internals
4. **Prototype Manipulation**: `__lookupSetter__()`, `__lookupGetter__()`, `Object.getPrototypeOf()`, `Object.setPrototypeOf()`
5. **Internal Property Access**: `.helper`, `.context`, `.owner`, `.navService` on DOM elements/components
6. **Hierarchy Traversal**: `getOwner()`, `getContext()` calls or loops traversing object hierarchies
7. **Dynamic Creation with Exploited Context**: Using stolen contexts for component creation
8. **Complex Invocation Chains**: `Function.prototype.call.apply()` or `Function.prototype.apply.call()`
9. **All contexts**: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences
**What to Ignore**:
- Standard LWC lifecycle methods
- Event handlers with proper this binding within same component
- Built-in JavaScript methods without external context manipulation
- Code loaded via loadScript() from static resources
#### How to report the Issue
**RuleId: lws-013**
**level: error**
**message: Context manipulation attack on imported framework class**
---
### Document.execCommand
#### How to Find the Issue
Flag `document.execCommand` with ONLY these dangerous commands:
- **insertHTML** - Enables HTML injection and XSS attacks
- **selectAll** - Can expose sensitive content via clipboard manipulation
**Detection Patterns**:
- Direct calls: `document.execCommand('insertHTML', ...)`
- Variables: `document.execCommand(cmdVar, ...)` where cmdVar could be dangerous
- String concatenation: `'insert' + 'HTML'`
- Bracket notation: `document['execCommand']('selectAll')`
- Unicode escape sequences
Do NOT flag safe commands (copy, cut, paste, bold, italic, underline, undo, redo).
#### How to report the Issue
**RuleId: lws-014**
**level: error**
**message: document.execCommand with {commandName} enables HTML injection or unauthorized data access**
---
### Insecure HTML Injection (DOM Sinks)
#### How to Find the Issue
Flag insecure HTML injection patterns through DOM sinks on any element, shadowRoot, or document objects:
**What to Look For**:
- **innerHTML assignments**: Direct assignment of untrusted content to innerHTML
- **outerHTML assignments**: Direct assignment of untrusted content to outerHTML
- **insertAdjacentHTML calls**: Using insertAdjacentHTML with untrusted content
- **setHTML/setHTMLUnsafe calls**: Using these methods with untrusted content
- **Dangerous content patterns**:
- Strings containing iframe elements with srcdoc attributes
- Strings containing script elements
- Dynamic HTML construction from variables
- **textContent with HTML**: Setting textContent to content that contains HTML markup
- **Any pattern where user input or external data is directly inserted into DOM sinks without proper sanitization**
**What to Ignore**:
- Safe DOM methods like createElement, appendChild, removeChild
- Proper use of textContent with plain text (no HTML)
- LWC template rendering and data binding
- Standard Lightning component usage
#### How to report the Issue
**RuleId: lws-015**
**level: error**
**message: Insecure HTML injection through {sinkName} enables XSS attacks**
---
### Map and Set Misuse
#### How to Find the Issue
Flag Map and Set misuse patterns:
**Direct Property Access/Assignment (CRITICAL)**:
- Using bracket notation: `map[key]` or `set[index]`
- Assigning with brackets: `map[key] = value` or `set[index] = value`
**Serialization Issues**:
- Using `JSON.stringify()` on Map or Set directly
- Passing Map/Set in decorators (e.g., `@wire`, `@track`)
- Sending Map/Set in event payloads or to child components
**Prototype Modification (CRITICAL)**:
- Adding properties to `Map.prototype` or `Set.prototype`
**What to Ignore**: DOM API usage, code unrelated to Map/Set misuse.
#### How to report the Issue
**RuleId: lws-016**
**level: error**
**message: Improper Map/Set usage bypasses internal data structures**
---
### Mutating Unknown Objects
#### How to Find the Issue
Flag mutations to objects not owned by the component:
**What to Flag**:
- **Event object mutations**: `event.detail.value = 'x'`, `event.target.customProp = true`
- **Parameter mutations**: `processConfig(config) { config.newProp = 'value'; }`
- **API response mutations**: `wireData.processed = true`, `response.items.customField = 123`
- **Mutations to properties received via @api**: `this.recordData.processed = true` where recordData is from @api
- **Non-standard properties on DOM elements**: `element.customProp = 123` (use dataset API instead)
- **Tracked property mutations**: Mutating wire data or external objects after storing in @track
- **Prototype/Host Object mutations**: `Array.prototype.custom = fn`, `document.foo = 'x'`
- **Mutations to objects from inherited methods**: Methods not defined in this component
**What to Ignore**:
- Objects created and owned by this component (not received from external sources)
- Standard DOM operations (createElement, appendChild, querySelector, innerHTML, textContent, classList)
- Standard event handling (addEventListener, removeEventListener)
- Mutations to cloned/copied objects (`const local = { ...external }; local.prop = 'x';`)
#### How to report the Issue
**RuleId: lws-017**
**level: error**
**message: Mutation of object not owned by component**
---
### Trusted Type Policy Names
#### How to Find the Issue
Flag `trustedTypes.createPolicy()` with these forbidden names:
- `'default'`
- `''` (empty string)
- `'lwsInternal'`
- `'trusted'`
Include string literals, variables, string concatenation, computed via unicode escapes, or accessed via Reflect APIs. Ignore policy content (second argument).
#### How to report the Issue
**RuleId: lws-018**
**level: error**
**message: Forbidden Trusted Type policy name '{policyName}' used**
---
### URL.createObjectURL with Restricted MIME Types
#### How to Find the Issue
Flag `URL.createObjectURL()` with restricted MIME types:
**Critical (Blocked)**:
- `text/javascript`
- Empty or undefined MIME types
**Warning (Must Be Scanned)**:
- `text/html` - Must be scanned for malicious content (script tags, XSS)
- `image/svg+xml` - Can contain embedded JavaScript
- `text/xml` - Must be scanned for malicious payloads
Trace back to Blob/File creation to extract MIME type. Include variable-based types, string concatenation, and template literals.
**Safe MIME Types** (don't flag): `image/*`, `video/*`, `audio/*`, `application/pdf`
**Detect Obfuscation**: `'text/' + 'javascript'`, template literals, conditional assignments
#### How to report the Issue
**RuleId: lws-019a**
**level: error**
**message: URL.createObjectURL with blocked MIME type '{mimeType}'**
**RuleId: lws-019b**
**level: warning**
**message: URL.createObjectURL with MIME type '{mimeType}' requires content scanning**
---
### URL Schemes
#### How to Find the Issue
Only `http`, `https`, and `about:blank` are allowed. Flag all disallowed schemes:
**Disallowed Schemes**:
- **Code Execution**: `javascript:`, `vbscript:` - Code execution, XSS attacks
- **CSP Bypass**: `data:`, `blob:` - Bypasses CSP, executable content
- **File System**: `file:` - File system access
- **Insecure Protocols**: `ftp:`, `ws:` - Insecure protocols
- **Potentially Exploitable**: `tel:`, `mailto:`
- **Custom Schemes**: Any non-standard URI schemes
**Where to Check**: HTML attributes (href, src, action), JavaScript strings/template literals, URL constructors, window.location/open, element.setAttribute, fetch/XHR URLs.
**Important**:
- Case insensitive detection (JavaScript:, JAVASCRIPT:)
- Watch for obfuscated schemes (`'java' + 'script:'`)
- `about:blank` ONLY allowed as exact literal, not with additional content
#### How to report the Issue
**RuleId: lws-020**
**level: error**
**message: Disallowed URL scheme '{scheme}' detected**
---
### SVG Animate Element Attributes
#### How to Find the Issue
Flag SVGAnimateElement's `to`, `from`, and `values` attributes containing URL values (`url(...)`).
**What to Flag**:
- `setAttribute('to', ...)` or `setAttribute('from', ...)` or `setAttribute('values', ...)` where the value contains `url(...)`
- Variable or template literal values that resolve to strings containing `url(...)`
**Critical Rules**:
1. **ONLY flag SVGAnimateElement**: The element must be created with `createElementNS('http://www.w3.org/2000/svg', 'animate')`
2. **ONLY these 3 attributes**: `to`, `from`, `values` - ignore all other attributes
3. **URL pattern required**: The attribute value must contain `url(...)` pattern
4. **Empty array if none found**: Return [] if no matches
**Note**: Informational only - LWS automatically sanitizes these URL values.
#### How to report the Issue
**RuleId: lws-021**
**level: warning**
**message: SVGAnimateElement attribute '{attributeName}' contains URL value (auto-sanitized by LWS)**
---
### Script Elements
#### How to Find the Issue
Flag direct script element creation and manipulation that could enable XSS attacks or CSP bypasses:
**What to Look For**:
- `document.createElement('script')` or `new HTMLScriptElement()`
- Script injection via innerHTML/outerHTML/insertAdjacentHTML
- Setting script.src to dynamic/untrusted URLs, blob URLs, or data URLs
- Setting script.textContent, script.text, or script.innerHTML with code
- All contexts: Loops, conditionals, event handlers, async callbacks, template literals, string concatenation, hidden by unicode escape sequences
#### How to report the Issue
**RuleId: lws-022**
**level: error**
**message: Direct script element creation or manipulation enables XSS attacks**
---
### Iframe Security
#### How to Find the Issue
Flag insecure iframe usage that leads to XSS or mXSS attacks:
**BLOCKED - srcdoc Attribute**:
- All srcdoc usage is blocked (bypasses CSP)
- `element.innerHTML = '<iframe srcdoc="..."></iframe>'`
- `iframe.setAttribute('srcdoc', '<html>...</html>')`
**BLOCKED - Dangerous src Protocols** (only http/https allowed):
- `javascript:` - `iframe.src = 'javascript:alert(1)'`
- `data:` - `iframe.src = 'data:text/html,<script>alert(1)</script>'`
- `blob:` - `iframe.src = URL.createObjectURL(blob)`
- `vbscript:` - `iframe.src = 'vbscript:msgbox(1)'`
- `file:` - `iframe.src = 'file:///etc/passwd'`
**BLOCKED - mXSS Attacks**:
- MathML/SVG/CDATA contexts combined with iframe srcdoc
- `math.setHTMLUnsafe('<style><!--</style><img src="--><mi><iframe srcdoc=\'...\'></iframe>"/>')`
- `div.innerHTML = '<svg><desc><iframe srcdoc=\'<script>...</script>\'></iframe></desc></svg>'`
**BLOCKED - Obfuscated Protocols**:
- Unicode escapes: `iframe.src = '\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074:alert(1)'`
- String concatenation: `iframe.src = ('java' + 'script:') + 'alert(1)'`
**ALLOWED**: Only http/https protocols
- `iframe.src = 'https://trusted-domain.com/content'`
- `div.innerHTML = '<iframe src="https://example.com"></iframe>'`
#### How to report the Issue
**RuleId: lws-023a**
**level: error**
**message: iframe srcdoc attribute usage bypasses CSP**
**RuleId: lws-023b**
**level: error**
**message: iframe src with disallowed protocol '{protocol}'**
---
scripts/check-lwc-import.sh#!/bin/bash
# check-lwc-import.sh <file>
#
# Determines whether a JS/TS file is an LWC module (imports from `lwc`).
# Used to gate LWS rules that only apply to LWC-managed code (e.g. lws-008).
# Exits 0 with `lwc-import=yes` on stdout when an import from the `lwc`
# module is present, or `lwc-import=no` when it is not. Exits non-zero on
# usage errors so the caller can distinguish "no import" from "bad input".
#
# A plain grep cannot tell a real `from 'lwc'` module specifier apart from the
# same text inside a string literal, template literal, or comment. So we do a
# lightweight lexical pass in python3 that removes comments and normalizes every
# string/template literal to the token `"lwc"` ONLY when its entire content is
# exactly `lwc` (otherwise `""`). After that pass, a real specifier survives as
# `from "lwc"` / `import "lwc"` / `import("lwc")`, while the phrase appearing
# inside a string, template, or comment collapses away and cannot match.
set -eu
if [ $# -ne 1 ]; then
echo "usage: check-lwc-import.sh <file>" >&2
exit 2
fi
file="$1"
if [ ! -f "$file" ]; then
echo "check-lwc-import.sh: file not found: $file" >&2
exit 2
fi
case "$file" in
*.js|*.ts|*.mjs|*.cjs) ;;
*)
echo "check-lwc-import.sh: unsupported extension (expected .js/.ts/.mjs/.cjs): $file" >&2
exit 2
;;
esac
if ! command -v python3 >/dev/null 2>&1; then
echo "check-lwc-import.sh: python3 is required but not installed" >&2
exit 2
fi
python3 - "$file" <<'PY'
import re
import sys
with open(sys.argv[1], "r", encoding="utf-8", errors="replace") as fh:
src = fh.read()
out = [] # cleaned code, with comments removed and string/template
# literals normalized to a content-aware token
i, n = 0, len(src)
def push_literal(content):
# Preserve the specifier only when the literal's whole content is exactly
# `lwc`; any other content (including a `from 'lwc'` phrase embedded in a
# longer string/template) collapses to an empty literal.
out.append('"lwc"' if content == "lwc" else '""')
def last_significant():
# The last non-whitespace character emitted so far — used to decide whether
# a `/` begins a regex literal (value position) or is a division operator
# (after a value). None at start of input.
for chunk in reversed(out):
s = chunk.rstrip()
if s:
return s[-1]
return None
while i < n:
c = src[i]
# line comment: drop to end of line (keep the newline for line structure)
if c == "/" and i + 1 < n and src[i + 1] == "/":
j = src.find("\n", i)
i = n if j == -1 else j
continue
# block comment: drop through the closing */
if c == "/" and i + 1 < n and src[i + 1] == "*":
j = src.find("*/", i + 2)
i = n if j == -1 else j + 2
out.append(" ")
continue
# single- or double-quoted string
if c == "'" or c == '"':
quote = c
i += 1
buf = []
while i < n and src[i] != quote:
if src[i] == "\\" and i + 1 < n: # keep escapes atomic
i += 2
buf.append("\\") # placeholder; content != lwc
continue
if src[i] == "\n": # unterminated string; stop
break
buf.append(src[i])
i += 1
i += 1 # consume closing quote
push_literal("".join(buf))
continue
# regex literal — only when `/` is in value position (not division). A
# regex begins the input or follows an operator/punctuator, never a value
# (identifier, number, `)`, `]`, `}`, or a quote). Its content is never a
# module specifier, so we drop it entirely; this stops `/from 'lwc'/` from
# being mistaken for an import.
if c == "/":
prev = last_significant()
if prev is None or prev in "=(,;:{[!&|?+-*%<>~^":
j = i + 1
in_class = False
while j < n:
ch = src[j]
if ch == "\\" and j + 1 < n:
j += 2
continue
if ch == "\n": # unterminated; bail out
break
if ch == "[":
in_class = True
elif ch == "]":
in_class = False
elif ch == "/" and not in_class:
j += 1
break
j += 1
out.append(" ") # regex collapses away
i = j
continue
# template literal (may span lines); treat ${...} as opaque content
if c == "`":
i += 1
buf = []
while i < n and src[i] != "`":
if src[i] == "\\" and i + 1 < n:
i += 2
buf.append("\\")
continue
buf.append(src[i])
i += 1
i += 1
push_literal("".join(buf))
continue
out.append(c)
i += 1
compact = re.sub(r"\s+", " ", "".join(out))
# A surviving `"lwc"` token appears only where the source had a real literal
# whose content was exactly `lwc`. Require it to sit in module-specifier
# position: after `from` (static import / re-export), or as a side-effect or
# dynamic `import`.
is_lwc = bool(
re.search(r'(^|[^\w$])from "lwc"', compact)
or re.search(r'(^|[^\w$])import "lwc"', compact)
or re.search(r'(^|[^\w$])import\("lwc"\)', compact)
)
print("lwc-import=yes" if is_lwc else "lwc-import=no")
PY
scripts/validate-sarif.sh#!/bin/bash
# validate-sarif.sh <sarif.json>
#
# Deterministic structural validation of a SARIF 2.1.0 score report emitted
# by experience-lwc-security-validate score mode. Verifies:
# 1. The file parses as JSON.
# 2. Top-level shape: {version:"2.1.0", runs:[{tool.driver.rules:[...], results:[...]}]}
# 3. Every `results[].ruleId` matches the LWS catalog pattern
# (lws-NNN[a-z]? | lws-tpl-NNN | lws-meta-NNN).
# 4. Every `results[].ruleId` is also declared in `tool.driver.rules[].id`.
# 5. Every `results[].level` is `error` or `warning`.
# 6. Every `results[]` has a `physicalLocation.artifactLocation.uri`
# and a `physicalLocation.region.startLine`.
#
# Prints one line per finding on stderr, then exits non-zero if any check
# failed. Exits 0 on success.
#
# Requires `jq` — the workflow already lists jq as a project prerequisite.
set -eu
if [ $# -ne 1 ]; then
echo "usage: validate-sarif.sh <sarif.json>" >&2
exit 2
fi
sarif="$1"
if [ ! -f "$sarif" ]; then
echo "validate-sarif.sh: file not found: $sarif" >&2
exit 2
fi
if ! command -v jq >/dev/null 2>&1; then
echo "validate-sarif.sh: jq is required but not installed" >&2
exit 2
fi
# 1. JSON parse
if ! jq empty "$sarif" >/dev/null 2>&1; then
echo "sarif-parse=fail file=$sarif reason=invalid-json" >&2
exit 1
fi
status=0
# 2. Top-level shape
version=$(jq -r '.version // ""' "$sarif")
if [ "$version" != "2.1.0" ]; then
echo "sarif-version=fail found='$version' expected='2.1.0'" >&2
status=1
fi
runs=$(jq -r '.runs | length' "$sarif" 2>/dev/null || echo 0)
if [ "$runs" -eq 0 ]; then
echo "sarif-runs=fail reason=empty-or-missing-runs" >&2
exit 1
fi
# tool.driver.rules and results MUST both be present as arrays — even for an
# empty result set, the workflow requires tool.driver.rules to be declared.
# `type` yields the JSON type or "null" when the path is missing, so this
# rejects absent or non-array values instead of silently treating them as [].
rules_type=$(jq -r '.runs[0].tool.driver.rules | type' "$sarif" 2>/dev/null || echo null)
if [ "$rules_type" != "array" ]; then
echo "sarif-rules=fail found='$rules_type' reason=tool.driver.rules-missing-or-not-array" >&2
status=1
fi
results_type=$(jq -r '.runs[0].results | type' "$sarif" 2>/dev/null || echo null)
if [ "$results_type" != "array" ]; then
echo "sarif-results=fail found='$results_type' reason=results-missing-or-not-array" >&2
# No results array to walk — report and exit now.
exit 1
fi
# Declared rules from tool.driver.rules[].id — one per line.
declared=$(jq -r '.runs[0].tool.driver.rules[]?.id // empty' "$sarif")
# Rule-ID pattern per Step 3 rules of the workflow.
rule_re='^(lws-[0-9]{3}[a-z]?|lws-tpl-[0-9]+|lws-meta-[0-9]+)$'
# 3-6. Walk results[]
result_count=$(jq -r '.runs[0].results | length' "$sarif" 2>/dev/null || echo 0)
if [ "$result_count" -eq 0 ]; then
# Empty results array is legal (no findings) once results and
# tool.driver.rules are both confirmed to be arrays above.
if [ "$status" -eq 0 ]; then
echo "sarif-validate=ok results=0"
fi
exit "$status"
fi
for i in $(seq 0 $((result_count - 1))); do
rid=$(jq -r ".runs[0].results[$i].ruleId // empty" "$sarif")
lvl=$(jq -r ".runs[0].results[$i].level // empty" "$sarif")
uri=$(jq -r ".runs[0].results[$i].locations[0].physicalLocation.artifactLocation.uri // empty" "$sarif")
line=$(jq -r ".runs[0].results[$i].locations[0].physicalLocation.region.startLine // empty" "$sarif")
if ! echo "$rid" | grep -Eq "$rule_re"; then
echo "result[$i].ruleId=fail found='$rid' reason=off-catalog-pattern" >&2
status=1
elif ! echo "$declared" | grep -Fxq "$rid"; then
echo "result[$i].ruleId=fail found='$rid' reason=not-declared-in-tool.driver.rules" >&2
status=1
fi
case "$lvl" in
error|warning) ;;
*)
echo "result[$i].level=fail found='$lvl' reason=must-be-error-or-warning" >&2
status=1
;;
esac
if [ -z "$uri" ]; then
echo "result[$i].physicalLocation.artifactLocation.uri=fail reason=missing" >&2
status=1
fi
if [ -z "$line" ]; then
echo "result[$i].physicalLocation.region.startLine=fail reason=missing" >&2
status=1
fi
done
if [ "$status" -eq 0 ]; then
echo "sarif-validate=ok results=$result_count"
fi
exit "$status"
SKILL.md---
name: experience-lwc-security-validate
description: "Use this skill as THE specialized Lightning Web Security (LWS) validator for a Lightning Web Component bundle (`.js`, `.ts`, `.html`, `.css`, `.js-meta.xml`) — the canonical LWS/Product-Security review for LWCs, NOT a generic code-security pass. It produces either a severity-ranked finding list with code-level remediations or a SARIF 2.1.0 JSON score report keyed by the `lws-001`…`lws-023b` rule catalog. TRIGGER when the user asks to review, audit, or check an LWC component for LWS compliance issues and recommend fixes, score a component's LWS/security compliance, find dangerous DOM APIs or blocked sinks (`eval`, `Function`, `document.write`, `innerHTML`, `document.createElement('script')`, global-scope assignment to `window`/`globalThis`, unsafe URL schemes), or emit a SARIF security report. DO NOT TRIGGER for generic non-LWC security review, for building a new LWC (use experience-lwc-generate), accessibility (WCAG 2.2), RTL/i18n, or Apex/Aura/server-side review."
metadata:
version: "1.0"
domains: ["Experience"]
relatedSkills:
- design-systems-slds-validate
- dx-code-analyzer-run
- experience-lwc-generate
cliTools:
- tool: ["jq"]
semver: ">=1.6"
- tool: ["python3"]
semver: ">=3.8"
---
<!-- adk-managed-skill -->
# Reviewing LWS Security
Run a structured Lightning Web Security (LWS) and Product Security compliance pass over a Lightning Web Component. Two output modes:
- **Review mode** (default) — severity-ranked findings + applied code fixes.
- **Score mode** — SARIF 2.1.0 JSON report keyed by the LWS rule catalog (`lws-001`…`lws-023b`) for downstream gating, eval scoring, or CI ingest.
Both modes use the same detection rules from the references; only the output format differs.
## When to Use
- The user asks for a "security review", "LWS check", "pre-ship security audit", or "compliance pass" on a specific LWC → review mode.
- The user asks to "score" a component's security or wants machine-readable findings to feed a gate or eval → score mode.
- Preparing a component for release and needing a unified security report.
- After implementing a fix, to verify no regression in security posture.
Do NOT use this skill for:
- Building new components (use `experience-lwc-generate`).
- Accessibility (apply WCAG 2.2 separately) or RTL review — out of scope.
- Gating a fix behind a feature flag (apply feature-flag gating after fixes land).
- Non-LWC security review (Apex, Aura, server-side) — out of scope.
## Prerequisites
- Component path (LWC bundle under `modules/…`).
- Access to the component's JS/TS, HTML templates, CSS, and `.js-meta.xml`.
- Output mode: `review` (default — find, fix, report) or `score` (find, emit SARIF JSON, do NOT modify code). Confirm with the user before starting if it isn't obvious from the request.
## Knowledge Bases
Each reference is the source of truth. Do not summarize from memory — open the reference, apply the guidelines, and cite the specific section you used in the report.
- Lightning Web Security (LWS) catalog: [LWS Security Expert](references/lws-security-expert.md) — blocked APIs and allowed alternatives.
- Rule catalog (`lws-001`…`lws-023b`): [Product Security Framework](references/security-analysis.md) — for every rule the catalog gives the detection patterns and the canonical SARIF `ruleId` / `level` / `message` template. **Score mode emits one SARIF result per match using these exact values.**
## Workflow
### Step 1 — Scope the review
Collect the component path and identify the files to review. Include every file in the component bundle: `.html`, `.js`/`.ts`, `.css`, `.js-meta.xml`, and any child components owned by the same team that are invoked from the target.
Note any existing feature-flag gates — findings that require code changes must respect them.
### Step 2 — Read the knowledge bases
Read [LWS Security Expert](references/lws-security-expert.md) and [Product Security Framework](references/security-analysis.md) top-to-bottom before judging. The LWS reference enumerates blocked DOM APIs and their allowed alternatives; the Product Security framework gives the severity taxonomy, the 23-rule SARIF catalog, and remediation patterns.
### Step 3 — Walk the rule catalog
Run every rule in [Product Security Framework](references/security-analysis.md) (`lws-001` through `lws-023b`) against the component bundle. For each rule:
1. Apply the **"How to Find the Issue"** patterns verbatim. Do NOT shortcut — each rule lists obfuscation patterns (bracket notation, unicode escapes, `Reflect.*`, string concatenation) you must consider.
2. For every match record: `ruleId`, `level` (`error` / `warning` from the catalog), `file`, `startLine`, `startColumn` (column 1 if unknown), `message` (use the catalog's `message` template, substituting any `{placeholder}` from the actual code).
3. If a rule has the prerequisite "Only analyze files that import from 'lwc'" (lws-008), gate it via `scripts/check-lwc-import.sh <file>` — the script prints `lwc-import=yes` when a `from 'lwc'` import is present and `lwc-import=no` otherwise. Skip the rule for that file when the answer is `no`.
This catalog is the canonical detection list; the JS/TS, HTML, and `.js-meta.xml` bullets that follow are *additional* checks beyond the SARIF rules.
### Step 4 — HTML template inspection (additional)
Walk each template for:
- `lwc:inner-html` usage — verify the source is trusted.
- Unescaped expressions feeding attributes LWS treats as sensitive (`href`, `src`, `srcdoc`, inline event handlers).
- Direct `style="…"` with bound expressions — candidates for CSS class swaps.
- Embedded `<iframe>` or `<object>` without sandboxing (Step 3 catches the `srcdoc` and protocol cases via lws-023a/lws-023b; this step catches missing `sandbox` attributes).
### Step 5 — Meta and configuration inspection (additional)
Inspect `.js-meta.xml` for:
- Over-broad API access (`lightning__FlowScreen`, `lightning__AppPage`, etc.) when the component doesn't need it.
- Public properties exposed that contain sensitive data.
- Missing `capabilities` restrictions for the target surface.
Inspect Apex bindings for:
- `@wire` to Apex methods without `@AuraEnabled(cacheable=true)` where caching is safe.
- Direct imperative calls that bypass permission checks.
Findings from Steps 4-5 use rule IDs `lws-tpl-001`…`lws-tpl-NNN` (HTML) and `lws-meta-001`…`lws-meta-NNN` (meta) — sequence numbers per finding within the report — so they don't collide with the SARIF catalog.
### Step 6 — Produce the report
Pick the output format based on the mode confirmed in Prerequisites.
#### Review mode (default)
Use [examples/review-report.md](examples/review-report.md) as the template — one bullet per finding under `## Security (LWS + Product)`, one totals line under `## Summary`.
Severity ordering: Critical → High → Medium → Low (map SARIF `error` → High, `warning` → Medium unless the rule says otherwise). Cite the reference section that produced each finding (e.g., "Product Security § lws-001 document.createProcessingInstruction").
#### Score mode
Emit a single SARIF 2.1.0 JSON document — and nothing else. No prose before or after. Do NOT write the JSON to a file; return it inline. Empty `results` array means no issues found.
Use [examples/score-report.sarif.json](examples/score-report.sarif.json) as the shape reference — same top-level structure (`$schema`, `version`, `runs[0].tool.driver.rules[]`, `runs[0].results[]`), populated with the actual rules that fired and the actual matches.
Rules:
- `ruleId` matches a catalog entry exactly (`lws-001`…`lws-023b`, or the `lws-tpl-*` / `lws-meta-*` namespaces from Steps 4-5).
- `level` is `error` for catalog rules marked `level: error` and `warning` for `level: warning`. No other values.
- `message.text` uses the catalog's `message` template with placeholders substituted (e.g., replace `{eventName}` with the actual event name found in code).
- One `result` per match. If a rule fires three times in a file, emit three results.
- Include only rules that fired in `tool.driver.rules`; an empty `results` array still requires `tool.driver.rules` to be present (use `[]`).
### Step 7 — Apply fixes (review mode only)
Skip in score mode — score mode is read-only.
For each accepted finding:
1. Edit the component files (HTML, JS/TS, CSS, meta.xml) to apply the fix.
2. Preserve existing correct behavior and existing feature-flag gates. If a gate is already configured for the same concern, leave it untouched. New feature-flag gates for phased rollout are out of scope for this skill — apply them separately.
3. Do NOT silently delete old code — preserve the original path where a gate is required.
4. Do NOT weaken the security posture to make tests pass; fix the test if it depends on the insecure pattern.
### Step 8 — Verify
- **Review mode**: Re-run Step 3's catalog walk against the updated files; every fixed finding must no longer appear. Run Jest tests and any component-level security tests. If fixes touched Apex access patterns, confirm permissions with the server-side reviewer.
- **Score mode**: Before returning, write the emitted SARIF to a temporary file and run `scripts/validate-sarif.sh <path>` — the script confirms the JSON parses, `version` is `2.1.0`, every `ruleId` matches the catalog pattern (`lws-NNN[a-z]?` / `lws-tpl-NNN` / `lws-meta-NNN`) and is declared in `tool.driver.rules`, every `level` is `error` or `warning`, and every result has a `physicalLocation.artifactLocation.uri` + `region.startLine`. Fix any failure before returning the SARIF.
## Cross-References
- Related skills:
- `experience-lwc-generate` — for authoring new LWC bundles that are security-compliant from the start.
- `design-systems-slds-validate` — SLDS/design-system compliance pass (accessibility overlaps with WCAG 2.2 — run separately).
- `dx-code-analyzer-run` — repo-wide static-analysis pass; use it alongside this skill for coverage beyond the LWS catalog.
## Verification
- Every catalog rule (`lws-001`…`lws-023b`) was evaluated against the bundle, not a hand-curated subset.
- Every finding has either been applied (review mode) or surfaced in the SARIF result (score mode), or carries an explicit deferred note with a reason.
- Each finding cites a specific catalog rule ID — no freeform "looks suspicious" entries.
- No new XSS sinks, unsafe URL flows, or blocked DOM APIs introduced by the fixes.
- Score-mode output is valid SARIF 2.1.0 JSON, returned inline, with no surrounding prose.