Skip to content

Commit 6aeddd5

Browse files
author
Jonathan D.A. Jewell
committed
Auto-commit: Sync changes [2026-02-18]
1 parent 65a59c3 commit 6aeddd5

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

src/Sanctify/Transform/Sanitize.hs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)

src/Sanctify/Transform/TypeHints.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Sanctify.Transform.TypeHints
1313

1414
-- * Full file transformation
1515
, addAllTypeHints
16+
, transformAddTypeHints
1617
) where
1718

1819
import Data.Text (Text)

0 commit comments

Comments
 (0)