# 1.8.4 untaint behavior

**URL:** <https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689>\
**Category:** Ruby\
**Created:** [January 18, 2006, 12:33am UTC](https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689 "2006-01-18T00:33:17Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![kelleysislander](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/f6c823/32.png) [@kelleysislander](https://www.ruby-forum.com/u/kelleysislander)\
**Post date:** [January 18, 2006, 12:33am UTC](https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689/1 "2006-01-18T00:33:17Z")

</div>

Hi,

I have a script running at $SAFE = 1, and after upgrading ruby  
from 1.8.2 to 1.8.4 (ruby 1.8.4 (2005-12-24) [i686-linux]),  
I started seeing SecurityError exceptions.

By adding printouts to the following code, I verified that  
line.untaint is occurring, and line.tainted? is false, but  
after the regexp match on line, the addr, port, and nick  
fields that come out of $1 $2 $3 are all tainted:

def read\_servers\_list(filename)  
servers = []  
IO.foreach($servers\_list\_filename) do |line|  
line.chop!  
line.strip!  
next if line.empty? || line =~ /\A\s\*#/  
if line =~ /\A[A-Za-z0-9\s.:-]+\z/  
line.untaint  
else  
logerr(“read\_servers\_list: refusing to untaint #{line.inspect}  
because of unexpected characters”)  
next  
end  
if line =~ /(\w+)\s+([^\s:]+)(?::(\d+))?/  
addr, port, nick = $2, $3 || “27910”, $1  
#  
##  
###  
### At this point,  
### line.tainted? =\> false  
### [addr,port,nick].all? {|o| o.tainted?} =\> true  
###  
##  
#  
servers \<\< ServerAddr.new(addr, port, nick)  
else  
logerr(“read\_servers\_list: couldn’t parse #{line.inspect}”)  
end  
end  
servers  
end

Is this a bug? Not sure why values extracted from an  
untainted object would be re-tainted. (Or have I made some  
crass mistake? 🙂

Thanks for your help,

Regards,

Bill

---

<div class="post-metadata">

**Author:** ![kelleysislander](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/f6c823/32.png) [@kelleysislander](https://www.ruby-forum.com/u/kelleysislander)\
**Post date:** [January 18, 2006, 1:48am UTC](https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689/2 "2006-01-18T01:48:41Z")

</div>

Hi,

I’ve reduced it to 10 lines or so, with no external I/O.  
I think this is a bug, unless I’m really doing something dumb.

```auto
#!/usr/bin/env ruby

$SAFE = 1 if $SAFE < 1

line = "vanilla tastyspleen.net:27912\n"
line.taint
line.chop!
line.strip!
line =~ /\A[A-Za-z0-9\s.:-]+\z/ #### this triggers it
line.untaint
if line =~ /(\w+)\s+([^\s:]+)(?::(\d+))?/
  addr, port, nick = $2, $3 || "27910", $1
  $stderr.puts "a=#{addr.tainted?} p=#{port.tainted?} n=#{nick.tainted?} 
l=#{line.tainted?} #{line}"
end

```

For me, (ruby 1.8.4 (2005-12-24) [i686-linux]), the above prints:

a=true p=true n=true l=false vanilla [tastyspleen.net:27912](http://tastyspleen.net:27912)

indicating line is not tainted, but the capture values pulled out of it  
are.

But, if I remove the “this triggers it” line, then the program prints:

a=false p=false n=false l=false vanilla [tastyspleen.net:27912](http://tastyspleen.net:27912)

which is how it used to behave under 1.8.2.

Here’s a one-liner version of it:

ruby -ve ‘$SAFE=1; l=“foo”.taint; l=~/(.)/; l.untaint; l=~/(.)/; p  
$1.tainted?’  
ruby 1.8.4 (2005-12-24) [i686-linux]  
true

ruby -ve ‘$SAFE=1; l=“foo”.taint; l.untaint; l=~/(.)/; p  
$1.tainted?’  
ruby 1.8.4 (2005-12-24) [i686-linux]  
false

Hope this helps,

Regards,

Bill

---

<div class="post-metadata">

**Author:** ![kelleysislander](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/f6c823/32.png) [@kelleysislander](https://www.ruby-forum.com/u/kelleysislander)\
**Post date:** [January 18, 2006, 3:55am UTC](https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689/3 "2006-01-18T03:55:29Z")

</div>

Hi,

At Wed, 18 Jan 2006 09:11:09 +0900,  
Bill K. wrote in [ruby-talk:176063]:

> I’ve reduced it to 10 lines or so, with no external I/O.  
> I think this is a bug, unless I’m really doing something dumb.

Probably.

The reason is underlying shared string object still keeps  
tainted after the original string got untainted.

This code shows a similar problem.

line = “x” \* 100  
line.taint  
line[0…-1]  
line.untaint  
p line.tainted?, line[0…-1].tainted?

# Index: array.c

RCS file: /cvs/ruby/src/ruby/array.c,v  
retrieving revision 1.186  
diff -U2 -p -r1.186 array.c  
— array.c 12 Dec 2005 16:46:59 -0000 1.186  
+++ array.c 18 Jan 2006 02:12:09 -0000  
@@ -73,4 +73,12 @@ rb\_ary\_freeze(VALUE ary)  
}

+/\* :nodoc: \*/  
+VALUE  
+rb\_ary\_untaint(VALUE ary)  
+{

- rb\_ary\_modify(ary);
- return rb\_obj\_untaint(ary);  
+}
- 

/\*

- call-seq:  
@@ -2852,4 +2860,5 @@ Init\_Array(void)  
rb\_define\_method(rb\_cArray, “to\_ary”, rb\_ary\_to\_ary\_m, 0);  
rb\_define\_method(rb\_cArray, “frozen?”, rb\_ary\_frozen\_p, 0);

- rb\_define\_method(rb\_cArray, “untaint”, rb\_ary\_untaint, 0);

+/\* :nodoc: \*/  
+VALUE  
+rb\_str\_untaint(VALUE str)  
+{

- rb\_str\_modify(str);
- return rb\_obj\_untaint(str);  
+}
- 

VALUE  
rb\_str\_dup\_frozen(VALUE str)  
@@ -4190,4 +4198,5 @@ Init\_String(void)  
rb\_define\_method(rb\_cString, “initialize”, rb\_str\_init, -1);  
rb\_define\_method(rb\_cString, “initialize\_copy”, rb\_str\_replace, 1);

- rb\_define\_method(rb\_cString, “untaint”, rb\_str\_untaint, 0);  
rb\_define\_method(rb\_cString, “\<=\>”, rb\_str\_cmp\_m, 1);  
rb\_define\_method(rb\_cString, “==”, rb\_str\_equal, 1);

---

<div class="post-metadata">

**Author:** ![kelleysislander](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/f6c823/32.png) [@kelleysislander](https://www.ruby-forum.com/u/kelleysislander)\
**Post date:** [January 18, 2006, 5:43am UTC](https://www.ruby-forum.com/t/1-8-4-untaint-behavior/52689/4 "2006-01-18T05:43:51Z")

</div>

Ni Nobu,

From: “nobuyoshi nakada” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> At Wed, 18 Jan 2006 09:11:09 +0900,  
> Bill K. wrote in [ruby-talk:176063]:
> 
> > I’ve reduced it to 10 lines or so, with no external I/O.  
> > I think this is a bug, unless I’m really doing something dumb.
> 
> Probably.
> 
> The reason is underlying shared string object still keeps  
> tainted after the original string got untainted.

[patch elided]

Awesome, thanks !!

Regards,

Bill
