Wyrdweaver has asked for the wisdom of the Perl Monks concerning the following question:

I'm using optional dependencies in some of my scripts and modules to add capability for 'MSWin32' platforms (namely, color with Win32::Console::ANSI and BASH-like command line parsing with Win32::CommandLine). Since these modules are only loadable on 'MSWin32' systems, they are loaded mid-run as optional dependencies. Because they are optional dependencies, they expose the script / module to the ". in @INC" threat vector.

ref: https://dzone.com/articles/security-separation-of-concerns-and-cve-2016-1238 @@ https://archive.is/sKbcs

Currently, the code is usually something like ...

# Module-Foo.pm use Term::ANSIColor; () = eval { require Win32::Console::ANSI } if 'MS +Win32' eq $^O;
and
# script-foo.pl no lib q{.}; # mitigate the ". in @INC" security threat vector when us +ing optional dependencies @ARGV = Win32::CommandLine::argv() if eval { require Win32::CommandLin +e };

For the module case, the OS/platform check at least narrows down the threat to only 'MSWin32' systems. But, especially in the case of modules, I'd like to remove the threat completely. Unfortunately, `no lib q{.}` is global, and I can't figure out a way to use it without affecting everything.

My other thought for modules was to add the optional dependencies as platform-specific required dependencies, but I'm trying to use the `dzil` build system with both 'Build.PL' and 'Makefile.PL', and I see no compatible method of specifying a platform-specific requirement.

Any thoughts on how to improve this?

Replies are listed 'Best First'.
Re: Mitigating ". in @INC" for optional dependencies
by shmem (Chancellor) on Sep 10, 2016 at 19:49 UTC
    no lib q{.}; # mitigate the ". in @INC" security threat vector # when using optional dependencies

    Well,if you talk security, you should use -T anyways. See perlrun and perlsec for "Taint mode", which implies "." not being included in @INC.

    As a (weaker) alternative, you could localize @INC in your eval block:

    @ARGV = Win32::CommandLine::argv() if eval { local @INC = grep !/^\.$/, @INC; # LHS is localized, RHS gets glob +al @INC require Win32::CommandLine; };

    This localized restriction then applies to all modules loaded by Win32::CommandLine as well, but not to subsequent code in your script-foo.pl.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      I like it.

      Are there any caveats for using the same idiom within modules...

      use Term::ANSIColor; () = eval { local @INC = grep !/^\.$/, @INC; require Win32::Console::A +NSI } if 'MSWin32' eq $^O;
      ?

      I'm advocating this idiom to any/all module authors using color in order to improve portability, and I don't want to impact their state negatively.

      Hopefully, 'Term::Color' will adopt it into it's synopsis text to further the cause.

        Are there any caveats for using the same idiom within modules...

        I can't see any caveats for using it within modules. It is the modules author's choice to permit or restrict the (arguably unsafe) "." in @INC. I'd consider modules relying on "." inside @INC to be broken. They shouldn't rely on "." but use something else to get their location, e.g. FindBin or __FILE__ or such - if they are not explicitly chameleonic modules.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Mitigating ". in @INC" for optional dependencies
by Corion (Patriarch) on Sep 10, 2016 at 18:24 UTC

    Have you considered simply writing your Makefile.PL manually if your release framework does not cater to your specific module's needs?

    If your main script puts . into @INC, it's not the purpose of your modules to second guess your main script.

    What actual problem are you trying to solve that . not being in @INC causes? I don't see how your scripts would behave differently whether @INC contains the current directory or not.

      Apologies to @Corion... the code, as originally posted, could be seen as pursuing the opposite of my actual goal. The code should have read ...

      no lib q{.} ...
      ... it has now been corrected.

      I'm trying to mitigate against the fact that '.' is included by default in @INC, and therefore a module could be "snuck in" if the optional dependency is not installed on the system.

      I just want to avoid looking in '.' when loading the optional module.

        Aaah - now I understand the situation a bit better.

        Please, don't do that from within your module. If the main script has (or leaves) . in @INC, it is not up to your module to question that. At program start, you could, in your main program, either convert . to an absolute path relative to the program, or the current directory, or remove it alltogether from @INC, but having modules implement their own handling makes only for a confusing situation where one module loads and the other doesn't, because they use different module loaders, instead of using require together with @INC as set up by the main program.

        If you decide to go the route of (locally) filtering @INC, at least output a warning if you remove . from @INC and loading the module fails.