@@ -2,8 +2,36 @@ use super::structs::Command;
22use crossterm:: style:: Stylize ;
33use pyo3:: types:: { PyAnyMethods , PyList , PyListMethods } ;
44use pyo3:: { PyResult , Python } ;
5+ use std:: fs;
6+ use std:: os:: unix:: fs:: { MetadataExt , PermissionsExt } ;
57use std:: path:: { Path , PathBuf } ;
68
9+ fn check_security ( path : & Path ) -> Result < ( ) , String > {
10+ let metadata = fs:: metadata ( path) . map_err ( |e| e. to_string ( ) ) ?;
11+ let file_uid = metadata. uid ( ) ;
12+ let current_uid = unsafe { libc:: geteuid ( ) } ;
13+
14+ if current_uid != file_uid {
15+ return Err ( format ! (
16+ "{} Running with UID {}, but file '{}' is owned by UID {}. Aborting to prevent privilege escalation." ,
17+ "SECURITY ERROR:" . red( ) . bold( ) ,
18+ current_uid,
19+ path. display( ) ,
20+ file_uid
21+ ) ) ;
22+ }
23+
24+ if metadata. permissions ( ) . mode ( ) & 0o022 == 0 {
25+ return Err ( format ! (
26+ "{} Python rule '{}' is writable by non-owners. Aborting to prevent privilege escalation." ,
27+ "SECURITY ERROR:" . red( ) . bold( ) ,
28+ path. display( )
29+ ) ) ;
30+ }
31+
32+ Ok ( ( ) )
33+ }
34+
735pub fn process_python_rules (
836 command : & Command ,
937 rule_paths : Vec < PathBuf > ,
@@ -20,6 +48,11 @@ pub fn process_python_rules(
2048 }
2149
2250 for rule_path in rule_paths {
51+ if let Err ( e) = check_security ( & rule_path) {
52+ eprintln ! ( "{}" , e) ;
53+ continue ;
54+ }
55+
2356 let module_name = match get_module_name ( & module_path, & rule_path) {
2457 Some ( module_name) => module_name,
2558 None => continue ,
0 commit comments