@@ -212,3 +212,128 @@ addExitAfterRedirect = concatMap processStmt
212212 ExprCall
213213 (Located pos $ ExprConstant $ QualifiedName [Name " exit" ] False )
214214 []
215+
216+ -- | Transform: escape outputs across the file
217+ transformSanitizeOutput :: PhpFile -> PhpFile
218+ transformSanitizeOutput file = file { phpStatements = map escapeStmt (phpStatements file) }
219+ where
220+ escapeStmt stmt@ (Located pos (StmtEcho exprs)) =
221+ Located pos $ StmtEcho $ map (wrapWithEscape $ detectEscapeContext stmt) exprs
222+ escapeStmt stmt = stmt
223+
224+ -- | Transform: sanitize superglobal inputs everywhere
225+ transformSanitizeInput :: PhpFile -> PhpFile
226+ transformSanitizeInput file = file { phpStatements = map (mapStatement sanitizeExpr) (phpStatements file) }
227+ where
228+ sanitizeExpr = mapExpr sanitizeSuperglobalAccess
229+
230+ -- | Transform: wrap unsafe $wpdb queries with prepare()
231+ transformSQLPrepare :: PhpFile -> PhpFile
232+ transformSQLPrepare file = file { phpStatements = map (mapStatement prepareQueries) (phpStatements file) }
233+ where
234+ prepareQueries = mapExpr prepareNode
235+
236+ prepareNode loc@ (Located pos expr@ (ExprMethodCall obj method args))
237+ | isWpdbObject obj
238+ , let name = unName method
239+ , name `elem` [" query" , " get_results" , " get_row" , " get_col" , " get_var" ]
240+ , not (null args)
241+ , let firstArg@ (Argument n argVal unpack) = head args
242+ , Just (query, params) <- convertToParameterizedQuery argVal
243+ = Located pos $ ExprMethodCall obj method $ Argument n (wrapWithPrepare query params) unpack : tail args
244+ prepareNode loc = loc
245+
246+ -- | Transform: ensure redirects end with exit()
247+ transformRedirectSafety :: PhpFile -> PhpFile
248+ transformRedirectSafety file = file { phpStatements = addExitAfterRedirect (phpStatements file) }
249+
250+ -- | Transform: modernize weak crypto helpers
251+ transformModernizeCrypto :: PhpFile -> PhpFile
252+ transformModernizeCrypto file = file { phpStatements = map (mapStatement modernizeExpr) (phpStatements file) }
253+ where
254+ modernizeExpr = mapExpr modernizeNode
255+
256+ modernizeNode loc@ (Located pos expr@ (ExprCall callee args)) =
257+ case functionName callee of
258+ Just fn | fn == " rand" -> Located pos $ ExprCall (makeConst " random_int" ) (map updateArg args)
259+ | fn == " md5" -> Located pos $ ExprCall (makeConst " hash" ) (Argument Nothing (Located pos $ ExprLiteral $ LitString " sha3-256" ) False : map updateArg args)
260+ | fn == " sha1" -> Located pos $ ExprCall (makeConst " sodium_crypto_generichash" ) (map updateArg args)
261+ _ -> loc
262+
263+ modernizeNode loc = loc
264+
265+ updateArg (Argument name value unpack) = Argument name (modernizeExpr value) unpack
266+
267+ makeConst name = Located pos $ ExprConstant $ QualifiedName [Name name] False
268+
269+ functionName (Located _ (ExprConstant (QualifiedName parts _))) = Just $ unName $ last parts
270+ functionName _ = Nothing
271+
272+ mapArgument :: (Located Expr -> Located Expr ) -> Argument -> Argument
273+ mapArgument f (Argument name value unpack) = Argument name (f value) unpack
274+
275+ mapExpr :: (Located Expr -> Located Expr ) -> Located Expr -> Located Expr
276+ mapExpr f (Located pos expr) = f $ Located pos (case expr of
277+ ExprBinary op l r -> ExprBinary op (mapExpr f l) (mapExpr f r)
278+ ExprUnary op e -> ExprUnary op (mapExpr f e)
279+ ExprAssign e1 e2 -> ExprAssign (mapExpr f e1) (mapExpr f e2)
280+ ExprAssignOp op e1 e2 -> ExprAssignOp op (mapExpr f e1) (mapExpr f e2)
281+ ExprTernary c t e -> ExprTernary (mapExpr f c) (fmap (mapExpr f) t) (mapExpr f e)
282+ ExprCall callee args -> ExprCall (mapExpr f callee) (map (mapArgument f) args)
283+ ExprMethodCall obj name args -> ExprMethodCall (mapExpr f obj) name (map (mapArgument f) args)
284+ ExprStaticCall qn name args -> ExprStaticCall qn name (map (mapArgument f) args)
285+ ExprNullsafeMethodCall obj name args -> ExprNullsafeMethodCall (mapExpr f obj) name (map (mapArgument f) args)
286+ ExprPropertyAccess obj name -> ExprPropertyAccess (mapExpr f obj) name
287+ ExprNullsafePropertyAccess obj name -> ExprNullsafePropertyAccess (mapExpr f obj) name
288+ ExprStaticPropertyAccess qn name -> ExprStaticPropertyAccess qn name
289+ ExprArrayAccess base idx -> ExprArrayAccess (mapExpr f base) (fmap (mapExpr f) idx)
290+ ExprNew qn args -> ExprNew qn (map (mapArgument f) args)
291+ ExprClosure {closureStatic= st, closureParams= ps, closureUses= us, closureReturn= ret, closureBody= body} ->
292+ ExprClosure st ps us ret (map (mapStatement f) body)
293+ ExprArrowFunction {arrowParams= params, arrowReturn= ret, arrowExpr= expr} ->
294+ ExprArrowFunction params ret (mapExpr f expr)
295+ ExprCast ty e -> ExprCast ty (mapExpr f e)
296+ ExprIsset exprs -> ExprIsset (map (mapExpr f) exprs)
297+ ExprEmpty e -> ExprEmpty (mapExpr f e)
298+ ExprEval e -> ExprEval (mapExpr f e)
299+ ExprInclude ty e -> ExprInclude ty (mapExpr f e)
300+ ExprYield m1 m2 -> ExprYield (fmap (mapExpr f) m1) (fmap (mapExpr f) m2)
301+ ExprYieldFrom e -> ExprYieldFrom (mapExpr f e)
302+ ExprThrow e -> ExprThrow (mapExpr f e)
303+ ExprClassConstAccess qn name -> ExprClassConstAccess qn name
304+ ExprConstant qn -> ExprConstant qn
305+ ExprShellExec t -> ExprShellExec t
306+ ExprHeredoc t -> ExprHeredoc t
307+ ExprList items -> ExprList (map (fmap (mapExpr f)) items)
308+ _ -> expr)
309+
310+ mapStatement :: (Located Expr -> Located Expr ) -> Located Statement -> Located Statement
311+ mapStatement f (Located pos stmt) = Located pos (case stmt of
312+ StmtExpr expr -> StmtExpr (f expr)
313+ StmtDecl decl -> StmtDecl decl
314+ StmtIf cond thenStmts elseStmts -> StmtIf (f cond) (map (mapStatement f) thenStmts) (fmap (map (mapStatement f)) elseStmts)
315+ StmtWhile cond body -> StmtWhile (f cond) (map (mapStatement f) body)
316+ StmtFor mInit mCond mUpdate body -> StmtFor (fmap f mInit) (fmap f mCond) (fmap f mUpdate) (map (mapStatement f) body)
317+ StmtForeach expr var forKey body -> StmtForeach (f expr) var forKey (map (mapStatement f) body)
318+ StmtSwitch expr cases -> StmtSwitch (f expr) (map (mapCase f) cases)
319+ StmtMatch expr arms -> StmtMatch (f expr) (map (mapArm f) arms)
320+ StmtTry tryBody catches finally -> StmtTry (map (mapStatement f) tryBody) (map (mapCatch f) catches) (fmap (map (mapStatement f)) finally)
321+ StmtReturn mExpr -> StmtReturn (fmap f mExpr)
322+ StmtThrow expr -> StmtThrow (f expr)
323+ StmtBreak n -> StmtBreak n
324+ StmtContinue n -> StmtContinue n
325+ StmtEcho exprs -> StmtEcho (map f exprs)
326+ StmtGlobal vars -> StmtGlobal vars
327+ StmtStatic pairs -> StmtStatic (map (ib -> (fst fib, fmap f (snd fib))) pairs)
328+ StmtUnset exprs -> StmtUnset (map f exprs)
329+ StmtDeclare decls body -> StmtDeclare decls (map (mapStatement f) body)
330+ StmtNoop -> StmtNoop )
331+
332+ mapCase :: (Located Expr -> Located Expr ) -> SwitchCase -> SwitchCase
333+ mapCase f (SwitchCase cond body) = SwitchCase (fmap (mapExpr f) cond) (map (mapStatement f) body)
334+
335+ mapArm :: (Located Expr -> Located Expr ) -> MatchArm -> MatchArm
336+ mapArm f (MatchArm cond result) = MatchArm (map (mapExpr f) cond) (mapExpr f result)
337+
338+ mapCatch :: (Located Expr -> Located Expr ) -> CatchClause -> CatchClause
339+ mapCatch f (CatchClause types var body) = CatchClause types var (map (mapStatement f) body)
0 commit comments