@@ -47,7 +47,35 @@ module LogInjection {
4747 * A logging operation, considered as a flow sink.
4848 */
4949 class LoggingAsSink extends Sink {
50- LoggingAsSink ( ) { this = any ( Logging write ) .getAnInput ( ) }
50+ LoggingAsSink ( ) {
51+ this = any ( Logging write ) .getAnInput ( ) and
52+ // since the inner implementation of the `logging.Logger.warn` function is
53+ // ```py
54+ // class Logger:
55+ // def warn(self, msg, *args, **kwargs):
56+ // warnings.warn("The 'warn' method is deprecated, "
57+ // "use 'warning' instead", DeprecationWarning, 2)
58+ // self.warning(msg, *args, **kwargs)
59+ // ```
60+ // any time we would report flow to such a logging sink, we can ALSO report
61+ // the flow to the `self.warning` sink -- obviously we don't want that.
62+ //
63+ // However, simply removing taint edges out of a sink is not a good enough solution,
64+ // since we would only flag one of the `logging.info` calls in the following example
65+ // due to use-use flow
66+ // ```py
67+ // logger.warn(user_controlled)
68+ // logger.warn(user_controlled)
69+ // ```
70+ //
71+ // The same approach is used in the command injection query.
72+ not exists ( Module loggingInit |
73+ loggingInit .getName ( ) = "logging.__init__" and
74+ this .getScope ( ) .getEnclosingModule ( ) = loggingInit and
75+ // do allow this call if we're analyzing logging/__init__.py as part of CPython though
76+ not exists ( loggingInit .getFile ( ) .getRelativePath ( ) )
77+ )
78+ }
5179 }
5280
5381 /**
0 commit comments